mac80211: bump to 5.10.16-1

This commit is contained in:
AmadeusGhost 2021-02-19 18:08:20 +08:00
parent 7e21f6ddd0
commit cc5be40bab
129 changed files with 6899 additions and 4884 deletions

View File

@ -10,10 +10,10 @@ include $(INCLUDE_DIR)/kernel.mk
PKG_NAME:=mac80211
PKG_VERSION:=5.4.56-1
PKG_VERSION:=5.10.16-1
PKG_RELEASE:=1
PKG_SOURCE_URL:=@KERNEL/linux/kernel/projects/backports/stable/v5.4.56/
PKG_HASH:=6030c2427e04f976cf53330087d0fdbb60ead7e1fecbd85e6f8e97ec0ed9a2eb
PKG_SOURCE_URL:=@KERNEL/linux/kernel/projects/backports/stable/v5.10.16/
PKG_HASH:=12856db780c5023edc47e2d18486eb3346bb7c82f1f2fc48deb3b163142f7d2d
PKG_SOURCE:=backports-$(PKG_VERSION).tar.xz
PKG_BUILD_DIR:=$(KERNEL_BUILD_DIR)/backports-$(PKG_VERSION)
@ -35,6 +35,7 @@ PKG_DRIVERS = \
PKG_CONFIG_DEPENDS:= \
CONFIG_PACKAGE_kmod-mac80211 \
CONFIG_PACKAGE_CFG80211_TESTMODE \
CONFIG_PACKAGE_MAC80211_DEBUGFS \
CONFIG_PACKAGE_MAC80211_MESH \
CONFIG_PACKAGE_MAC80211_TRACING \
@ -56,7 +57,6 @@ config_package=$(if $(CONFIG_PACKAGE_kmod-$(1)),m)
config-y:= \
WLAN \
NL80211_TESTMODE \
CFG80211_WEXT \
CFG80211_CERTIFICATION_ONUS \
MAC80211_RC_MINSTREL \
@ -80,6 +80,7 @@ config-y:= \
WLAN_VENDOR_ZYDAS \
config-$(call config_package,cfg80211) += CFG80211
config-$(CONFIG_PACKAGE_CFG80211_TESTMODE) += NL80211_TESTMODE
config-$(call config_package,mac80211) += MAC80211
config-$(CONFIG_PACKAGE_MAC80211_MESH) += MAC80211_MESH
@ -108,6 +109,20 @@ define KernelPackage/cfg80211/description
cfg80211 is the Linux wireless LAN (802.11) configuration API.
endef
define KernelPackage/cfg80211/config
if PACKAGE_kmod-cfg80211
config PACKAGE_CFG80211_TESTMODE
bool "Enable testmode command support"
default n
help
This is typically used for tests and calibration during
manufacturing, or vendor specific debugging features
endif
endef
define KernelPackage/mac80211
$(call KernelPackage/mac80211/Default)
TITLE:=Linux 802.11 Wireless Networking Stack
@ -250,7 +265,7 @@ endef
define KernelPackage/mac80211-hwsim
$(call KernelPackage/mac80211/Default)
TITLE:=mac80211 HW simulation device
DEPENDS+= +kmod-mac80211 +@DRIVER_11AC_SUPPORT +@DRIVER_11N_SUPPORT +@DRIVER_11W_SUPPORT
DEPENDS+= +kmod-mac80211 +@DRIVER_11AC_SUPPORT +@DRIVER_11N_SUPPORT
FILES:=$(PKG_BUILD_DIR)/drivers/net/wireless/mac80211_hwsim.ko
AUTOLOAD:=$(call AutoProbe,mac80211_hwsim)
endef
@ -259,7 +274,7 @@ endef
define KernelPackage/mt7601u
$(call KernelPackage/mac80211/Default)
TITLE:=MT7601U-based USB dongles Wireless Driver
DEPENDS+= +kmod-mac80211 +@DRIVER_11N_SUPPORT +@DRIVER_11W_SUPPORT @USB_SUPPORT +kmod-usb-core +mt7601u-firmware
DEPENDS+= +kmod-mac80211 +@DRIVER_11N_SUPPORT @USB_SUPPORT +kmod-usb-core +mt7601u-firmware
FILES:=$(PKG_BUILD_DIR)/drivers/net/wireless/mediatek/mt7601u/mt7601u.ko
AUTOLOAD:=$(call AutoProbe,mt7601u)
endef
@ -275,7 +290,7 @@ endef
define KernelPackage/p54-common
$(call KernelPackage/p54/Default)
DEPENDS+= @(PCI_SUPPORT||USB_SUPPORT) +kmod-mac80211 +kmod-lib-crc-ccitt +@DRIVER_11W_SUPPORT
DEPENDS+= @(PCI_SUPPORT||USB_SUPPORT) +kmod-mac80211 +kmod-lib-crc-ccitt
TITLE+= (COMMON)
FILES:=$(PKG_BUILD_DIR)/drivers/net/wireless/intersil/p54/p54common.ko
endef
@ -373,7 +388,7 @@ $(eval $(call Download,zd1211rw))
define KernelPackage/zd1211rw
$(call KernelPackage/mac80211/Default)
TITLE:=Zydas ZD1211 support
DEPENDS+= @USB_SUPPORT +kmod-usb-core +kmod-mac80211 +@DRIVER_11W_SUPPORT
DEPENDS+= @USB_SUPPORT +kmod-usb-core +kmod-mac80211
FILES:=$(PKG_BUILD_DIR)/drivers/net/wireless/zydas/zd1211rw/zd1211rw.ko
AUTOLOAD:=$(call AutoProbe,zd1211rw)
endef

View File

@ -1,12 +1,13 @@
PKG_DRIVERS += \
ath ath5k ath6kl ath6kl-sdio ath6kl-usb ath9k ath9k-common ath9k-htc ath10k \
carl9170 owl-loader ar5523
carl9170 owl-loader ar5523 wil6210
PKG_CONFIG_DEPENDS += \
CONFIG_PACKAGE_ATH_DEBUG \
CONFIG_PACKAGE_ATH_DFS \
CONFIG_PACKAGE_ATH_SPECTRAL \
CONFIG_PACKAGE_ATH_DYNACK \
CONFIG_ATH9K_HWRNG \
CONFIG_ATH9K_SUPPORT_PCOEM \
CONFIG_ATH9K_TX99 \
CONFIG_ATH10K_LEDS \
@ -20,7 +21,8 @@ ifdef CONFIG_PACKAGE_MAC80211_DEBUGFS
ATH10K_DEBUGFS \
CARL9170_DEBUGFS \
ATH5K_DEBUG \
ATH6KL_DEBUG
ATH6KL_DEBUG \
WIL6210_DEBUGFS
endif
ifdef CONFIG_PACKAGE_MAC80211_TRACING
@ -28,7 +30,8 @@ ifdef CONFIG_PACKAGE_MAC80211_TRACING
ATH10K_TRACING \
ATH6KL_TRACING \
ATH_TRACEPOINTS \
ATH5K_TRACER
ATH5K_TRACER \
WIL6210_TRACING
endif
config-$(call config_package,ath) += ATH_CARDS ATH_COMMON ATH_REG_DYNAMIC_USER_REG_HINTS
@ -43,6 +46,7 @@ config-$(CONFIG_TARGET_ath79) += ATH9K_AHB
config-$(CONFIG_TARGET_ipq40xx) += ATH10K_AHB
config-$(CONFIG_PCI) += ATH9K_PCI
config-$(CONFIG_ATH_USER_REGD) += ATH_USER_REGD
config-$(CONFIG_ATH9K_HWRNG) += ATH9K_HWRNG
config-$(CONFIG_ATH9K_SUPPORT_PCOEM) += ATH9K_PCOEM
config-$(CONFIG_ATH9K_TX99) += ATH9K_TX99
config-$(CONFIG_ATH9K_UBNTHSR) += ATH9K_UBNTHSR
@ -66,6 +70,8 @@ config-$(call config_package,ath6kl-usb) += ATH6KL_USB
config-$(call config_package,carl9170) += CARL9170
config-$(call config_package,ar5523) += AR5523
config-$(call config_package,wil6210) += WIL6210
define KernelPackage/ath/config
if PACKAGE_kmod-ath
config ATH_USER_REGD
@ -132,7 +138,7 @@ define KernelPackage/ath5k
$(call KernelPackage/mac80211/Default)
TITLE:=Atheros 5xxx wireless cards support
URL:=https://wireless.wiki.kernel.org/en/users/drivers/ath5k
DEPENDS+= @(PCI_SUPPORT||TARGET_ath25) +kmod-ath +@DRIVER_11W_SUPPORT
DEPENDS+= @(PCI_SUPPORT||TARGET_ath25) +kmod-ath
FILES:=$(PKG_BUILD_DIR)/drivers/net/wireless/ath/ath5k/ath5k.ko
AUTOLOAD:=$(call AutoProbe,ath5k)
endef
@ -184,7 +190,7 @@ define KernelPackage/ath9k-common
TITLE:=Atheros 802.11n wireless devices (common code for ath9k and ath9k_htc)
URL:=https://wireless.wiki.kernel.org/en/users/drivers/ath9k
HIDDEN:=1
DEPENDS+= @PCI_SUPPORT||USB_SUPPORT||TARGET_ath79 +kmod-ath +@DRIVER_11N_SUPPORT +@DRIVER_11W_SUPPORT
DEPENDS+= @PCI_SUPPORT||USB_SUPPORT||TARGET_ath79 +kmod-ath +@DRIVER_11N_SUPPORT
FILES:= \
$(PKG_BUILD_DIR)/drivers/net/wireless/ath/ath9k/ath9k_common.ko \
$(PKG_BUILD_DIR)/drivers/net/wireless/ath/ath9k/ath9k_hw.ko
@ -207,6 +213,12 @@ endef
define KernelPackage/ath9k/config
config ATH9K_HWRNG
bool "Add wireless noise as source of randomness to kernel entropy pool"
depends on PACKAGE_kmod-ath9k
select PACKAGE_kmod-random-core
default n
config ATH9K_SUPPORT_PCOEM
bool "Support chips used in PC OEM cards"
depends on PACKAGE_kmod-ath9k
@ -242,7 +254,7 @@ define KernelPackage/ath10k
$(call KernelPackage/mac80211/Default)
TITLE:=Atheros 802.11ac wireless cards support
URL:=https://wireless.wiki.kernel.org/en/users/drivers/ath10k
DEPENDS+= @PCI_SUPPORT +kmod-ath +@DRIVER_11N_SUPPORT +@DRIVER_11AC_SUPPORT +@DRIVER_11W_SUPPORT \
DEPENDS+= @PCI_SUPPORT +kmod-ath +@DRIVER_11N_SUPPORT +@DRIVER_11AC_SUPPORT \
+ATH10K_THERMAL:kmod-hwmon-core +ATH10K_THERMAL:kmod-thermal
FILES:= \
$(PKG_BUILD_DIR)/drivers/net/wireless/ath/ath10k/ath10k_core.ko \
@ -273,7 +285,7 @@ endef
define KernelPackage/carl9170
$(call KernelPackage/mac80211/Default)
TITLE:=Driver for Atheros AR9170 USB sticks
DEPENDS:=@USB_SUPPORT +kmod-mac80211 +kmod-ath +kmod-usb-core +kmod-input-core +@DRIVER_11N_SUPPORT +@DRIVER_11W_SUPPORT +carl9170-firmware
DEPENDS:=@USB_SUPPORT +kmod-mac80211 +kmod-ath +kmod-usb-core +kmod-input-core +@DRIVER_11N_SUPPORT +carl9170-firmware
FILES:=$(PKG_BUILD_DIR)/drivers/net/wireless/ath/carl9170/carl9170.ko
AUTOLOAD:=$(call AutoProbe,carl9170)
endef
@ -302,3 +314,11 @@ define KernelPackage/ar5523
FILES:=$(PKG_BUILD_DIR)/drivers/net/wireless/ath/ar5523/ar5523.ko
AUTOLOAD:=$(call AutoProbe,ar5523)
endef
define KernelPackage/wil6210
$(call KernelPackage/mac80211/Default)
TITLE:=QCA/Wilocity 60g WiFi card wil6210 support
DEPENDS+= @PCI_SUPPORT +kmod-mac80211 +wil6210-firmware
FILES:=$(PKG_BUILD_DIR)/drivers/net/wireless/ath/wil6210/wil6210.ko
AUTOLOAD:=$(call AutoProbe,wil6210)
endef

View File

@ -433,7 +433,7 @@ define KernelPackage/brcmfmac
$(call KernelPackage/mac80211/Default)
TITLE:=Broadcom IEEE802.11n USB FullMAC WLAN driver
URL:=https://wireless.wiki.kernel.org/en/users/drivers/brcm80211
DEPENDS+= @USB_SUPPORT +kmod-cfg80211 +@DRIVER_11N_SUPPORT +@DRIVER_11AC_SUPPORT +@DRIVER_11W_SUPPORT \
DEPENDS+= @USB_SUPPORT +kmod-cfg80211 +@DRIVER_11N_SUPPORT +@DRIVER_11AC_SUPPORT \
+kmod-brcmutil +BRCMFMAC_SDIO:kmod-mmc @!TARGET_uml \
+BRCMFMAC_USB:kmod-usb-core +BRCMFMAC_USB:brcmfmac-firmware-usb
FILES:=$(PKG_BUILD_DIR)/drivers/net/wireless/broadcom/brcm80211/brcmfmac/brcmfmac.ko

View File

@ -28,11 +28,13 @@ drv_mac80211_init_device_config() {
config_add_string path phy 'macaddr:macaddr'
config_add_string hwmode
config_add_string tx_burst
config_add_string distance
config_add_int beacon_int chanbw frag rts
config_add_int rxantenna txantenna antenna_gain txpower distance
config_add_int rxantenna txantenna antenna_gain txpower
config_add_boolean noscan ht_coex acs_exclude_dfs
config_add_array ht_capab
config_add_array channels
config_add_array scan_list
config_add_boolean \
rxldpc \
short_gi_80 \
@ -100,7 +102,6 @@ mac80211_hostapd_setup_base() {
json_select config
[ "$auto_channel" -gt 0 ] && channel=acs_survey
[ "$auto_channel" -gt 0 ] && json_get_values channel_list channels
[ "$auto_channel" -gt 0 ] && json_get_vars acs_exclude_dfs
[ -n "$acs_exclude_dfs" ] && [ "$acs_exclude_dfs" -gt 0 ] &&
@ -108,6 +109,10 @@ mac80211_hostapd_setup_base() {
json_get_vars noscan ht_coex vendor_vht
json_get_values ht_capab_list ht_capab tx_burst
json_get_values channel_list channels
[ "$auto_channel" = 0 ] && [ -z "$channel_list" ] && \
channel_list="$channel"
set_default noscan 0
@ -117,8 +122,8 @@ mac80211_hostapd_setup_base() {
ieee80211n=1
ht_capab=
case "$htmode" in
VHT20|HT20) ;;
HT40*|VHT40|VHT80|VHT160)
VHT20|HT20|HE20) ;;
HT40*|VHT40|VHT80|VHT160|HE40|HE80|HE160)
case "$hwmode" in
a)
case "$(( ($channel / 4) % 2 ))" in
@ -188,19 +193,21 @@ mac80211_hostapd_setup_base() {
# 802.11ac
enable_ac=0
vht_oper_chwidth=0
vht_center_seg0=
idx="$channel"
case "$htmode" in
VHT20) enable_ac=1;;
VHT40)
VHT20|HE20) enable_ac=1;;
VHT40|HE40)
case "$(( ($channel / 4) % 2 ))" in
1) idx=$(($channel + 2));;
0) idx=$(($channel - 2));;
esac
enable_ac=1
append base_cfg "vht_oper_chwidth=0" "$N"
append base_cfg "vht_oper_centr_freq_seg0_idx=$idx" "$N"
vht_center_seg0=$idx
;;
VHT80)
VHT80|HE80)
case "$(( ($channel / 4) % 4 ))" in
1) idx=$(($channel + 6));;
2) idx=$(($channel + 2));;
@ -208,19 +215,20 @@ mac80211_hostapd_setup_base() {
0) idx=$(($channel - 6));;
esac
enable_ac=1
append base_cfg "vht_oper_chwidth=1" "$N"
append base_cfg "vht_oper_centr_freq_seg0_idx=$idx" "$N"
vht_oper_chwidth=1
vht_center_seg0=$idx
;;
VHT160)
VHT160|HE160)
case "$channel" in
36|40|44|48|52|56|60|64) idx=50;;
100|104|108|112|116|120|124|128) idx=114;;
esac
enable_ac=1
append base_cfg "vht_oper_chwidth=2" "$N"
append base_cfg "vht_oper_centr_freq_seg0_idx=$idx" "$N"
vht_oper_chwidth=2
vht_center_seg0=$idx
;;
esac
[ "$hwmode" = "a" ] || enable_ac=0
if [ "$enable_ac" != "0" -o "$vendor_vht" = "1" ]; then
json_get_vars \
@ -249,6 +257,9 @@ mac80211_hostapd_setup_base() {
vht_cap="$(($vht_cap | $cap))"
done
append base_cfg "vht_oper_chwidth=$vht_oper_chwidth" "$N"
append base_cfg "vht_oper_centr_freq_seg0_idx=$vht_center_seg0" "$N"
cap_rx_stbc=$((($vht_cap >> 8) & 7))
[ "$rx_stbc" -lt "$cap_rx_stbc" ] && cap_rx_stbc="$rx_stbc"
vht_cap="$(( ($vht_cap & ~(0x700)) | ($cap_rx_stbc << 8) ))"
@ -319,6 +330,25 @@ mac80211_hostapd_setup_base() {
[ -n "$vht_capab" ] && append base_cfg "vht_capab=$vht_capab" "$N"
fi
# 802.11ax
enable_ax=0
case "$htmode" in
HE*) enable_ax=1 ;;
esac
if [ "$enable_ax" != "0" ]; then
append base_cfg "ieee80211ax=1" "$N"
[ "$hwmode" = "a" ] && {
append base_cfg "he_oper_chwidth=$vht_oper_chwidth" "$N"
append base_cfg "he_oper_centr_freq_seg0_idx=$vht_center_seg0" "$N"
}
append base_cfg "he_default_pe_duration=4" "$N"
append base_cfg "he_rts_threshold=1023" "$N"
append base_cfg "he_su_beamformer=1" "$N"
append base_cfg "he_su_beamformee=1" "$N"
append base_cfg "he_mu_beamformer=1" "$N"
fi
hostapd_prepare_device_config "$hostapd_conf_file" nl80211
cat >> "$hostapd_conf_file" <<EOF
${channel:+channel=$channel}
@ -342,7 +372,7 @@ mac80211_hostapd_setup_bss() {
hostapd_cfg=
append hostapd_cfg "$type=$ifname" "$N"
hostapd_set_bss_options hostapd_cfg "$vif" || return 1
hostapd_set_bss_options hostapd_cfg "$phy" "$vif" || return 1
json_get_vars wds wds_bridge dtim_period max_listen_int start_disabled
set_default wds 0
@ -366,7 +396,7 @@ mac80211_get_addr() {
local phy="$1"
local idx="$(($2 + 1))"
head -n $(($macidx + 1)) /sys/class/ieee80211/${phy}/addresses | tail -n1
head -n $idx /sys/class/ieee80211/${phy}/addresses | tail -n1
}
mac80211_generate_mac() {
@ -505,7 +535,7 @@ mac80211_iw_interface_add() {
mac80211_prepare_vif() {
json_select config
json_get_vars ifname mode ssid wds powersave macaddr enable
json_get_vars ifname mode ssid wds powersave macaddr enable wpa_psk_file vlan_file
[ -n "$ifname" ] || ifname="wlan${phy#phy}${if_idx:+-$if_idx}"
if_idx=$((${if_idx:-0} + 1))
@ -523,6 +553,12 @@ mac80211_prepare_vif() {
json_add_object data
json_add_string ifname "$ifname"
json_close_object
[ "$mode" == "ap" ] && {
[ -z "$wpa_psk_file" ] && hostapd_set_psk "$ifname"
[ -z "$vlan_file" ] && hostapd_set_vlan "$ifname"
}
json_select config
# It is far easier to delete and create the desired interface
@ -590,7 +626,13 @@ mac80211_setup_supplicant() {
local add_sp=0
local spobj="$(ubus -S list | grep wpa_supplicant.${ifname})"
wpa_supplicant_prepare_interface "$ifname" nl80211 || return 1
[ "$enable" = 0 ] && {
ubus call wpa_supplicant.${phy} config_remove "{\"iface\":\"$ifname\"}"
ip link set dev "$ifname" down
iw dev "$ifname" del
return 0
}
wpa_supplicant_prepare_interface "$ifname" nl80211 || {
iw dev "$ifname" del
return 1
@ -607,18 +649,17 @@ mac80211_setup_supplicant() {
[ "$spobj" ] && ubus call wpa_supplicant config_remove "{\"iface\":\"$ifname\"}"
add_sp=1
fi
[ "$enable" = 0 ] && {
ubus call wpa_supplicant config_remove "{\"iface\":\"$ifname\"}"
ip link set dev "$ifname" down
return 0
}
[ -z "$spobj" ] && add_sp=1
NEW_MD5_SP=$(test -e "${_config}" && md5sum ${_config})
OLD_MD5_SP=$(uci -q -P /var/state get wireless._${phy}.md5_${ifname})
if [ "$add_sp" = "1" ]; then
wpa_supplicant_run "$ifname" "$hostapd_ctrl"
else
ubus call $spobj reload
[ "${NEW_MD5_SP}" == "${OLD_MD5_SP}" ] || ubus call $spobj reload
fi
uci -q -P /var/state set wireless._${phy}.md5_${ifname}="${NEW_MD5_SP}"
return 0
}
mac80211_setup_supplicant_noctl() {
@ -765,7 +806,6 @@ mac80211_setup_vif() {
[ "$vif_enable" = 1 ] || action=down
if [ "$mode" != "ap" ] || [ "$ifname" = "$ap_ifname" ]; then
logger ip link set dev "$ifname" $action
ip link set dev "$ifname" "$action" || {
wireless_setup_vif_failed IFUP_ERROR
json_select ..
@ -777,6 +817,7 @@ mac80211_setup_vif() {
case "$mode" in
mesh)
wireless_vif_parse_encryption
[ -z "$htmode" ] && htmode="NOHT";
freq="$(get_freq "$phy" "$channel")"
if [ "$wpa" -gt 0 -o "$auto_channel" -gt 0 ] || chan_is_dfs "$phy" "$channel"; then
mac80211_setup_supplicant $vif_enable || failed=1
@ -857,6 +898,7 @@ drv_mac80211_setup() {
rxantenna txantenna \
frag rts beacon_int:100 htmode
json_get_values basic_rate_list basic_rate
json_get_values scan_list scan_list
json_select ..
find_phy || {
@ -923,8 +965,8 @@ drv_mac80211_setup() {
[ "$rxantenna" = "all" ] && rxantenna=0xffffffff
iw phy "$phy" set antenna $txantenna $rxantenna >/dev/null 2>&1
iw phy "$phy" set antenna_gain $antenna_gain
iw phy "$phy" set distance "$distance"
iw phy "$phy" set antenna_gain $antenna_gain >/dev/null 2>&1
iw phy "$phy" set distance "$distance" >/dev/null 2>&1
if [ -n "$txpower" ]; then
iw phy "$phy" set txpower fixed "${txpower%%.*}00"
@ -954,8 +996,8 @@ drv_mac80211_setup() {
OLD_MD5=$(uci -q -P /var/state get wireless._${phy}.md5)
if [ "${NEWAPLIST}" != "${OLDAPLIST}" ]; then
mac80211_vap_cleanup hostapd "${OLDAPLIST}"
[ -n "${NEWAPLIST}" ] && mac80211_iw_interface_add "$phy" "${NEWAPLIST%% *}" __ap || return
fi
[ -n "${NEWAPLIST}" ] && mac80211_iw_interface_add "$phy" "${NEWAPLIST%% *}" __ap
local add_ap=0
local primary_ap=${NEWAPLIST%% *}
[ -n "$hostapd_ctrl" ] && {
@ -966,22 +1008,25 @@ drv_mac80211_setup() {
no_reload=$?
if [ "$no_reload" != "0" ]; then
mac80211_vap_cleanup hostapd "${OLDAPLIST}"
[ -n "${NEWAPLIST}" ] && mac80211_iw_interface_add "$phy" "${NEWAPLIST%% *}" __ap || return
mac80211_vap_cleanup wpa_supplicant "$(uci -q -P /var/state get wireless._${phy}.splist)"
mac80211_vap_cleanup none "$(uci -q -P /var/state get wireless._${phy}.umlist)"
sleep 2
mac80211_iw_interface_add "$phy" "${NEWAPLIST%% *}" __ap
for_each_interface "sta adhoc mesh monitor" mac80211_prepare_vif
fi
}
fi
if [ "$no_reload" != "0" ]; then
add_ap=1
ubus wait_for hostapd
ubus call hostapd config_add "{\"iface\":\"$primary_ap\", \"config\":\"${hostapd_conf_file}\"}"
local hostapd_pid=$(ubus call service list '{"name": "hostapd"}' | jsonfilter -l 1 -e "@['hostapd'].instances['hostapd'].pid")
wireless_add_process "$hostapd_pid" "/usr/sbin/hostapd" 1
local hostapd_res="$(ubus call hostapd config_add "{\"iface\":\"$primary_ap\", \"config\":\"${hostapd_conf_file}\"}")"
ret="$?"
[ "$ret" != 0 -o -z "$hostapd_res" ] && {
wireless_setup_failed HOSTAPD_START_FAILED
return
}
wireless_add_process "$(jsonfilter -s "$hostapd_res" -l 1 -e @.pid)" "/usr/sbin/hostapd" 1 1
fi
ret="$?"
[ "$ret" != 0 ] && {
wireless_setup_failed HOSTAPD_START_FAILED
return
}
}
uci -q -P /var/state set wireless._${phy}.aplist="${NEWAPLIST}"
uci -q -P /var/state set wireless._${phy}.md5="${NEW_MD5}"
@ -1029,8 +1074,6 @@ list_phy_interfaces() {
}
drv_mac80211_teardown() {
wireless_process_kill_all
json_select data
json_get_vars phy
json_select ..

View File

@ -88,6 +88,12 @@ detect_mac80211() {
iw phy "$dev" info | grep -q 'VHT Capabilities' && htmode="VHT80"
}
iw phy "$dev" info | grep -q '\* 5.... MHz \[' && {
mode_band="ad"
channel=$(iw phy "$dev" info | grep '\* 5.... MHz \[' | grep '(disabled)' -v -m 1 | sed 's/[^[]*\[\|\|\].*//g')
iw phy "$dev" info | grep -q 'Capabilities:' && htmode="HT20"
}
[ -n "$htmode" ] && ht_capab="set wireless.radio${devidx}.htmode=$htmode"
path="$(mac80211_phy_to_path "$dev")"
@ -104,6 +110,7 @@ detect_mac80211() {
set wireless.radio${devidx}.hwmode=11${mode_band}
${dev_id}
${ht_capab}
set wireless.radio${devidx}.country=US
set wireless.radio${devidx}.disabled=0
set wireless.default_radio${devidx}=wifi-iface

View File

@ -15,7 +15,7 @@ config-$(call config_package,ipw2200) += IPW2200
define KernelPackage/iwlwifi
$(call KernelPackage/mac80211/Default)
DEPENDS:= +kmod-mac80211 @PCI_SUPPORT +@DRIVER_11N_SUPPORT +@DRIVER_11AC_SUPPORT +@DRIVER_11W_SUPPORT
DEPENDS:= +kmod-mac80211 @PCI_SUPPORT +@DRIVER_11N_SUPPORT +@DRIVER_11AC_SUPPORT
TITLE:=Intel AGN Wireless support
FILES:= \
$(PKG_BUILD_DIR)/drivers/net/wireless/intel/iwlwifi/iwlwifi.ko \

View File

@ -1,7 +1,7 @@
--- a/drivers/net/wireless/ath/ath10k/Kconfig
+++ b/drivers/net/wireless/ath/ath10k/Kconfig
@@ -87,6 +87,12 @@ config ATH10K_TRACING
---help---
@@ -86,6 +86,12 @@ config ATH10K_TRACING
help
Select this to ath10k use tracing infrastructure.
+config ATH10K_THERMAL

View File

@ -11,7 +11,7 @@ Signed-off-by: Christian Lamparter <chunkeey@gmail.com>
--- a/drivers/net/wireless/ath/ath9k/ath9k_pci_owl_loader.c
+++ b/drivers/net/wireless/ath/ath9k/ath9k_pci_owl_loader.c
@@ -104,6 +104,7 @@ static void owl_fw_cb(const struct firmw
@@ -103,6 +103,7 @@ static void owl_fw_cb(const struct firmw
{
struct pci_dev *pdev = (struct pci_dev *)context;
struct owl_ctx *ctx = (struct owl_ctx *)pci_get_drvdata(pdev);
@ -19,7 +19,7 @@ Signed-off-by: Christian Lamparter <chunkeey@gmail.com>
struct pci_bus *bus;
complete(&ctx->eeprom_load);
@@ -119,6 +120,16 @@ static void owl_fw_cb(const struct firmw
@@ -118,6 +119,16 @@ static void owl_fw_cb(const struct firmw
goto release;
}
@ -36,7 +36,7 @@ Signed-off-by: Christian Lamparter <chunkeey@gmail.com>
if (ath9k_pci_fixup(pdev, (const u16 *)fw->data, fw->size))
goto release;
@@ -138,8 +149,14 @@ release:
@@ -137,8 +148,14 @@ release:
static const char *owl_get_eeprom_name(struct pci_dev *pdev)
{
struct device *dev = &pdev->dev;

View File

@ -1,6 +1,6 @@
--- a/drivers/net/wireless/ath/Makefile
+++ b/drivers/net/wireless/ath/Makefile
@@ -14,10 +14,10 @@ ath-objs := main.o \
@@ -15,10 +15,10 @@ ath-objs := main.o \
regd.o \
hw.o \
key.o \

View File

@ -79,7 +79,7 @@
+
config ATH_DEBUG
bool "Atheros wireless debugging"
---help---
help
--- a/local-symbols
+++ b/local-symbols
@@ -85,6 +85,7 @@ ADM8211=

View File

@ -4,15 +4,15 @@
NL80211_RRF_NO_OFDM)
/* We allow IBSS on these on a case by case basis by regulatory domain */
-#define ATH9K_5GHZ_5150_5350 REG_RULE(5150-10, 5350+10, 80, 0, 30,\
+#define ATH9K_5GHZ_5150_5350 REG_RULE(5150-10, 5240+10, 80, 0, 30, 0),\
-#define ATH_5GHZ_5150_5350 REG_RULE(5150-10, 5350+10, 80, 0, 30,\
+#define ATH_5GHZ_5150_5350 REG_RULE(5150-10, 5240+10, 80, 0, 30, 0),\
+ REG_RULE(5260-10, 5350+10, 80, 0, 30,\
NL80211_RRF_NO_IR)
#define ATH9K_5GHZ_5470_5850 REG_RULE(5470-10, 5850+10, 80, 0, 30,\
#define ATH_5GHZ_5470_5850 REG_RULE(5470-10, 5850+10, 80, 0, 30,\
NL80211_RRF_NO_IR)
@@ -62,57 +63,56 @@ static struct reg_dmn_pair_mapping *ath_
#define ATH9K_5GHZ_NO_MIDBAND ATH9K_5GHZ_5150_5350, \
ATH9K_5GHZ_5725_5850
#define ATH_5GHZ_NO_MIDBAND ATH_5GHZ_5150_5350, \
ATH_5GHZ_5725_5850
+#define REGD_RULES(...) \
+ .reg_rules = { __VA_ARGS__ }, \
@ -25,8 +25,8 @@
.alpha2 = "99",
- .reg_rules = {
+ REGD_RULES(
ATH9K_2GHZ_ALL,
ATH9K_5GHZ_ALL,
ATH_2GHZ_ALL,
ATH_5GHZ_ALL,
- }
+ )
};
@ -37,9 +37,9 @@
.alpha2 = "99",
- .reg_rules = {
+ REGD_RULES(
ATH9K_2GHZ_CH01_11,
ATH9K_2GHZ_CH12_13,
ATH9K_5GHZ_NO_MIDBAND,
ATH_2GHZ_CH01_11,
ATH_2GHZ_CH12_13,
ATH_5GHZ_NO_MIDBAND,
- }
+ )
};
@ -50,8 +50,8 @@
.alpha2 = "99",
- .reg_rules = {
+ REGD_RULES(
ATH9K_2GHZ_CH01_11,
ATH9K_5GHZ_NO_MIDBAND,
ATH_2GHZ_CH01_11,
ATH_5GHZ_NO_MIDBAND,
- }
+ )
};
@ -62,8 +62,8 @@
.alpha2 = "99",
- .reg_rules = {
+ REGD_RULES(
ATH9K_2GHZ_CH01_11,
ATH9K_5GHZ_ALL,
ATH_2GHZ_CH01_11,
ATH_5GHZ_ALL,
- }
+ )
};
@ -74,9 +74,9 @@
.alpha2 = "99",
- .reg_rules = {
+ REGD_RULES(
ATH9K_2GHZ_CH01_11,
ATH9K_2GHZ_CH12_13,
ATH9K_5GHZ_ALL,
ATH_2GHZ_CH01_11,
ATH_2GHZ_CH12_13,
ATH_5GHZ_ALL,
- }
+ )
};

View File

@ -1,6 +1,6 @@
--- a/net/wireless/reg.c
+++ b/net/wireless/reg.c
@@ -3039,6 +3039,8 @@ void regulatory_hint_country_ie(struct w
@@ -3252,6 +3252,8 @@ void regulatory_hint_country_ie(struct w
enum environment_cap env = ENVIRON_ANY;
struct regulatory_request *request = NULL, *lr;
@ -9,7 +9,7 @@
/* IE len must be evenly divisible by 2 */
if (country_ie_len & 0x01)
return;
@@ -3290,6 +3292,7 @@ static bool is_wiphy_all_set_reg_flag(en
@@ -3503,6 +3505,7 @@ static bool is_wiphy_all_set_reg_flag(en
void regulatory_hint_disconnect(void)
{

View File

@ -1,6 +1,6 @@
--- a/drivers/net/wireless/ath/ath9k/init.c
+++ b/drivers/net/wireless/ath/ath9k/init.c
@@ -831,6 +831,7 @@ static const struct ieee80211_iface_limi
@@ -830,6 +830,7 @@ static const struct ieee80211_iface_limi
BIT(NL80211_IFTYPE_AP) },
{ .max = 1, .types = BIT(NL80211_IFTYPE_P2P_CLIENT) |
BIT(NL80211_IFTYPE_P2P_GO) },

View File

@ -11,7 +11,7 @@ drivers/net/wireless/ath/ath5k/debug.c | 86 ++++++++++++++++++++++++++++++++
--- a/drivers/net/wireless/ath/ath5k/debug.c
+++ b/drivers/net/wireless/ath/ath5k/debug.c
@@ -822,6 +822,97 @@ static const struct file_operations fops
@@ -803,6 +803,97 @@ static const struct file_operations fops
.llseek = default_llseek,
};
@ -109,7 +109,7 @@ drivers/net/wireless/ath/ath5k/debug.c | 86 ++++++++++++++++++++++++++++++++
/* debugfs: queues etc */
@@ -1016,6 +1107,8 @@ ath5k_debug_init_device(struct ath5k_hw
@@ -997,6 +1088,8 @@ ath5k_debug_init_device(struct ath5k_hw
debugfs_create_file("queue", 0600, phydir, ah, &fops_queue);
debugfs_create_bool("32khz_clock", 0600, phydir,
&ah->ah_use_32khz_clock);

View File

@ -0,0 +1,34 @@
From d946085ff5a331de64e91a2e3c96b9ca79d740f5 Mon Sep 17 00:00:00 2001
From: David Bauer <mail@david-bauer.net>
Date: Mon, 15 Jun 2020 00:10:34 +0200
Subject: [PATCH] ath9k: enabled MFP capability unconditionally
ath9k will already fallback on software-crypto for chipsets not
supporting IEEE802.11w (MFP). So advertising MFP is not dependent
on disabling HW crypto for all traffic entirely.
Signed-off-by: David Bauer <mail@david-bauer.net>
---
drivers/net/wireless/ath/ath9k/init.c | 4 +---
1 file changed, 1 insertion(+), 3 deletions(-)
--- a/drivers/net/wireless/ath/ath9k/init.c
+++ b/drivers/net/wireless/ath/ath9k/init.c
@@ -927,6 +927,7 @@ static void ath9k_set_hw_capab(struct at
ieee80211_hw_set(hw, HOST_BROADCAST_PS_BUFFERING);
ieee80211_hw_set(hw, SUPPORT_FAST_XMIT);
ieee80211_hw_set(hw, SUPPORTS_CLONED_SKBS);
+ ieee80211_hw_set(hw, MFP_CAPABLE);
if (ath9k_ps_enable)
ieee80211_hw_set(hw, SUPPORTS_PS);
@@ -939,9 +940,6 @@ static void ath9k_set_hw_capab(struct at
IEEE80211_RADIOTAP_MCS_HAVE_STBC;
}
- if (AR_SREV_9160_10_OR_LATER(sc->sc_ah) || ath9k_modparam_nohwcrypt)
- ieee80211_hw_set(hw, MFP_CAPABLE);
-
hw->wiphy->features |= NL80211_FEATURE_ACTIVE_MONITOR |
NL80211_FEATURE_AP_MODE_CHAN_WIDTH_CHANGE |
NL80211_FEATURE_P2P_GO_CTWIN;

View File

@ -62,7 +62,7 @@
debugfs_create_devm_seqfile(sc->dev, "interrupt", sc->debug.debugfs_phy,
--- a/drivers/net/wireless/ath/ath9k/hw.h
+++ b/drivers/net/wireless/ath/ath9k/hw.h
@@ -521,6 +521,12 @@ enum {
@@ -522,6 +522,12 @@ enum {
ATH9K_RESET_COLD,
};
@ -75,7 +75,7 @@
struct ath9k_hw_version {
u32 magic;
u16 devid;
@@ -809,6 +815,8 @@ struct ath_hw {
@@ -810,6 +816,8 @@ struct ath_hw {
u32 ah_flags;
s16 nf_override;
@ -84,7 +84,7 @@
bool reset_power_on;
bool htc_reset_init;
@@ -1074,6 +1082,7 @@ void ath9k_hw_check_nav(struct ath_hw *a
@@ -1076,6 +1084,7 @@ void ath9k_hw_check_nav(struct ath_hw *a
bool ath9k_hw_check_alive(struct ath_hw *ah);
bool ath9k_hw_setpower(struct ath_hw *ah, enum ath9k_power_mode mode);
@ -125,7 +125,7 @@
REG_SET_BIT(ah, AR_BTCOEX_WL_LNADIV, AR_BTCOEX_WL_LNADIV_FORCE_ON);
--- a/drivers/net/wireless/ath/ath9k/main.c
+++ b/drivers/net/wireless/ath/ath9k/main.c
@@ -528,6 +528,11 @@ irqreturn_t ath_isr(int irq, void *dev)
@@ -531,6 +531,11 @@ irqreturn_t ath_isr(int irq, void *dev)
if (test_bit(ATH_OP_HW_RESET, &common->op_flags))
return IRQ_HANDLED;

View File

@ -1,6 +1,6 @@
--- a/drivers/net/wireless/ath/ath9k/hw.h
+++ b/drivers/net/wireless/ath/ath9k/hw.h
@@ -722,6 +722,7 @@ struct ath_spec_scan {
@@ -723,6 +723,7 @@ struct ath_spec_scan {
* @config_pci_powersave:
* @calibrate: periodic calibration for NF, ANI, IQ, ADC gain, ADC-DC
*
@ -8,7 +8,7 @@
* @spectral_scan_config: set parameters for spectral scan and enable/disable it
* @spectral_scan_trigger: trigger a spectral scan run
* @spectral_scan_wait: wait for a spectral scan run to finish
@@ -744,6 +745,7 @@ struct ath_hw_ops {
@@ -745,6 +746,7 @@ struct ath_hw_ops {
struct ath_hw_antcomb_conf *antconf);
void (*antdiv_comb_conf_set)(struct ath_hw *ah,
struct ath_hw_antcomb_conf *antconf);
@ -55,7 +55,7 @@
ops->spectral_scan_config = ar9003_hw_spectral_scan_config;
--- a/drivers/net/wireless/ath/ath9k/init.c
+++ b/drivers/net/wireless/ath/ath9k/init.c
@@ -819,7 +819,8 @@ static void ath9k_init_txpower_limits(st
@@ -818,7 +818,8 @@ static void ath9k_init_txpower_limits(st
if (ah->caps.hw_caps & ATH9K_HW_CAP_5GHZ)
ath9k_init_band_txpower(sc, NL80211_BAND_5GHZ);
@ -66,7 +66,7 @@
static const struct ieee80211_iface_limit if_limits[] = {
@@ -1015,6 +1016,18 @@ static void ath9k_set_hw_capab(struct at
wiphy_ext_feature_set(hw->wiphy, NL80211_EXT_FEATURE_AIRTIME_FAIRNESS);
wiphy_ext_feature_set(hw->wiphy, NL80211_EXT_FEATURE_CAN_REPLACE_PTK0);
}
+static void ath_get_initial_entropy(struct ath_softc *sc)
@ -110,7 +110,7 @@
static inline void ath9k_hw_set_bt_ant_diversity(struct ath_hw *ah, bool enable)
--- a/drivers/net/wireless/ath/ath9k/ar5008_phy.c
+++ b/drivers/net/wireless/ath/ath9k/ar5008_phy.c
@@ -1320,9 +1320,30 @@ void ar5008_hw_init_rate_txpower(struct
@@ -1349,9 +1349,30 @@ void ar5008_hw_init_rate_txpower(struct
}
}
@ -141,7 +141,7 @@
static const u32 ar5416_cca_regs[6] = {
AR_PHY_CCA,
AR_PHY_CH1_CCA,
@@ -1337,6 +1358,8 @@ int ar5008_hw_attach_phy_ops(struct ath_
@@ -1366,6 +1387,8 @@ int ar5008_hw_attach_phy_ops(struct ath_
if (ret)
return ret;

View File

@ -1,6 +1,6 @@
--- a/drivers/net/wireless/ath/ath9k/ar5008_phy.c
+++ b/drivers/net/wireless/ath/ath9k/ar5008_phy.c
@@ -949,55 +949,6 @@ static bool ar5008_hw_ani_control_new(st
@@ -978,55 +978,6 @@ static bool ar5008_hw_ani_control_new(st
* on == 0 means more noise imm
*/
u32 on = param ? 1 : 0;

View File

@ -337,9 +337,9 @@
#include "btcoex.h"
+#include "hsr.h"
u8 ath9k_parse_mpdudensity(u8 mpdudensity)
{
@@ -649,6 +650,7 @@ void ath_reset_work(struct work_struct *
static void ath9k_flush(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
u32 queues, bool drop);
@@ -652,6 +653,7 @@ void ath_reset_work(struct work_struct *
static int ath9k_start(struct ieee80211_hw *hw)
{
struct ath_softc *sc = hw->priv;
@ -347,7 +347,7 @@
struct ath_hw *ah = sc->sc_ah;
struct ath_common *common = ath9k_hw_common(ah);
struct ieee80211_channel *curchan = sc->cur_chan->chandef.chan;
@@ -727,6 +729,11 @@ static int ath9k_start(struct ieee80211_
@@ -730,6 +732,11 @@ static int ath9k_start(struct ieee80211_
AR_GPIO_OUTPUT_MUX_AS_OUTPUT);
}

View File

@ -13,7 +13,7 @@
static int ath9k_init_softc(u16 devid, struct ath_softc *sc,
const struct ath_bus_ops *bus_ops)
{
@@ -758,6 +764,9 @@ static int ath9k_init_softc(u16 devid, s
@@ -757,6 +763,9 @@ static int ath9k_init_softc(u16 devid, s
if (ret)
goto err_hw;

View File

@ -0,0 +1,49 @@
From: Felix Fietkau <nbd@nbd.name>
Date: Sun, 14 Feb 2021 19:45:50 +0100
Subject: [PATCH] ath9k: fix transmitting to stations in dynamic SMPS mode
When transmitting to a receiver in dynamic SMPS mode, all transmissions that
use multiple spatial streams need to be sent using CTS-to-self or RTS/CTS to
give the receiver's extra chains some time to wake up.
This fixes the tx rate getting stuck at <= MCS7 for some clients, especially
Intel ones, which make aggressive use of SMPS.
Cc: stable@vger.kernel.org
Reported-by: Martin Kennedy <hurricos@gmail.com>
Signed-off-by: Felix Fietkau <nbd@nbd.name>
---
--- a/drivers/net/wireless/ath/ath9k/ath9k.h
+++ b/drivers/net/wireless/ath/ath9k/ath9k.h
@@ -179,7 +179,8 @@ struct ath_frame_info {
s8 txq;
u8 keyix;
u8 rtscts_rate;
- u8 retries : 7;
+ u8 retries : 6;
+ u8 dyn_smps : 1;
u8 baw_tracked : 1;
u8 tx_power;
enum ath9k_key_type keytype:2;
--- a/drivers/net/wireless/ath/ath9k/xmit.c
+++ b/drivers/net/wireless/ath/ath9k/xmit.c
@@ -1271,6 +1271,11 @@ static void ath_buf_set_rate(struct ath_
is_40, is_sgi, is_sp);
if (rix < 8 && (tx_info->flags & IEEE80211_TX_CTL_STBC))
info->rates[i].RateFlags |= ATH9K_RATESERIES_STBC;
+ if (rix >= 8 && fi->dyn_smps) {
+ info->rates[i].RateFlags |=
+ ATH9K_RATESERIES_RTS_CTS;
+ info->flags |= ATH9K_TXDESC_CTSENA;
+ }
info->txpower[i] = ath_get_rate_txpower(sc, bf, rix,
is_40, false);
@@ -2114,6 +2119,7 @@ static void setup_frame_info(struct ieee
fi->keyix = an->ps_key;
else
fi->keyix = ATH9K_TXKEYIX_INVALID;
+ fi->dyn_smps = sta && sta->smps_mode == IEEE80211_SMPS_DYNAMIC;
fi->keytype = keytype;
fi->framelen = framelen;
fi->tx_power = txpower;

View File

@ -14,7 +14,7 @@ Signed-off-by: Sven Eckelmann <sven@open-mesh.com>
--- a/drivers/net/wireless/ath/ath10k/core.c
+++ b/drivers/net/wireless/ath/ath10k/core.c
@@ -3074,6 +3074,16 @@ int ath10k_core_register(struct ath10k *
@@ -3189,6 +3189,16 @@ int ath10k_core_register(struct ath10k *
queue_work(ar->workqueue, &ar->register_work);

View File

@ -26,7 +26,7 @@ Forwarded: https://patchwork.kernel.org/patch/11367055/
--- a/drivers/net/wireless/ath/ath10k/htt.h
+++ b/drivers/net/wireless/ath/ath10k/htt.h
@@ -2226,7 +2226,7 @@ struct htt_rx_chan_info {
@@ -2242,7 +2242,7 @@ struct htt_rx_chan_info {
* Should be: sizeof(struct htt_host_rx_desc) + max rx MSDU size,
* rounded up to a cache line size.
*/

View File

@ -1,6 +1,6 @@
--- a/drivers/net/wireless/ath/ath10k/mac.c
+++ b/drivers/net/wireless/ath/ath10k/mac.c
@@ -8677,6 +8677,21 @@ static int ath10k_mac_init_rd(struct ath
@@ -9713,6 +9713,21 @@ static int ath10k_mac_init_rd(struct ath
return 0;
}
@ -22,7 +22,7 @@
int ath10k_mac_register(struct ath10k *ar)
{
static const u32 cipher_suites[] = {
@@ -9003,6 +9018,12 @@ int ath10k_mac_register(struct ath10k *a
@@ -10062,6 +10077,12 @@ int ath10k_mac_register(struct ath10k *a
ar->hw->weight_multiplier = ATH10K_AIRTIME_WEIGHT_MULTIPLIER;

View File

@ -1,144 +0,0 @@
From: Sebastian Gottschall <s.gottschall@dd-wrt.com>
current handling of peer_bw_rxnss_override parameter is based on guessing the VHT160/8080 capability by rx rate. this is wrong and may lead
to a non initialized peer_bw_rxnss_override parameter which is required since VHT160 operation mode only supports 2x2 chainmasks in addition the original code
initialized the parameter with wrong masked values.
This patch uses the peer phymode and peer nss information for correct initialisation of the peer_bw_rxnss_override parameter.
if this peer information is not available, we initialize the parameter by minimum nss which is suggested by QCA as temporary workaround according
to the QCA sourcecodes.
Signed-off-by: Sebastian Gottschall <s.gottschall@dd-wrt.com>
v2: remove debug messages
v3: apply some cosmetics, update documentation
v4: fix compile warning and truncate nss to maximum of 2x2 since current chipsets only support 2x2 at vht160
v5: handle maximum nss for chipsets supportig vht160 with 1x1 only
v7: use more simple code variant and take care about hw/sw chainmask configuration
v8: fix some code style issues
v9: use SM/MS macros from code.h to simplify shift/mask handling
---
drivers/net/wireless/ath/ath10k/mac.c | 54 +++++++++++++++++++--------
drivers/net/wireless/ath/ath10k/wmi.c | 7 +---
drivers/net/wireless/ath/ath10k/wmi.h | 14 ++++++-
3 files changed, 52 insertions(+), 23 deletions(-)
--- a/drivers/net/wireless/ath/ath10k/mac.c
+++ b/drivers/net/wireless/ath/ath10k/mac.c
@@ -2515,7 +2515,7 @@ static void ath10k_peer_assoc_h_vht(stru
const u16 *vht_mcs_mask;
u8 ampdu_factor;
u8 max_nss, vht_mcs;
- int i;
+ int i, nss160;
if (WARN_ON(ath10k_mac_vif_chan(vif, &def)))
return;
@@ -2575,23 +2575,45 @@ static void ath10k_peer_assoc_h_vht(stru
__le16_to_cpu(vht_cap->vht_mcs.tx_highest);
arg->peer_vht_rates.tx_mcs_set = ath10k_peer_assoc_h_vht_limit(
__le16_to_cpu(vht_cap->vht_mcs.tx_mcs_map), vht_mcs_mask);
+ arg->peer_bw_rxnss_override = 0;
+ nss160 = 1; /* 1x1 default config for VHT160 */
- ath10k_dbg(ar, ATH10K_DBG_MAC, "mac vht peer %pM max_mpdu %d flags 0x%x\n",
- sta->addr, arg->peer_max_mpdu, arg->peer_flags);
+ /* only local 4x4 configuration do support 2x2 for VHT160,
+ * everything else must use 1x1
+ */
- if (arg->peer_vht_rates.rx_max_rate &&
- (sta->vht_cap.cap & IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_MASK)) {
- switch (arg->peer_vht_rates.rx_max_rate) {
- case 1560:
- /* Must be 2x2 at 160Mhz is all it can do. */
- arg->peer_bw_rxnss_override = 2;
- break;
- case 780:
- /* Can only do 1x1 at 160Mhz (Long Guard Interval) */
- arg->peer_bw_rxnss_override = 1;
- break;
- }
+ if (ar->cfg_rx_chainmask == 15)
+ nss160 = arg->peer_num_spatial_streams <= 2 ? 1 : 2;
+
+ /* if peer provides 1x1 nss160 information using max rate
+ * vht information, we reduce local nss160 to 1x1.
+ * consider that it has been observed that some client
+ * devices provide zero here, no matter which transmission
+ * rate is possible. in that case the local nss configuration
+ * will be used at maxmimum configuration possible. (see above)
+ */
+
+ if (arg->peer_vht_rates.rx_max_rate == 780)
+ nss160 = 1;
+
+ /* in case if peer is connected with vht160 or vht80+80,
+ * we need to properly adjust rxnss parameters otherwise
+ * firmware will raise a assert
+ */
+ switch (arg->peer_phymode) {
+ case MODE_11AC_VHT80_80:
+ arg->peer_bw_rxnss_override = BW_NSS_FWCONF_80_80(nss160);
+ /* fall through */
+ case MODE_11AC_VHT160:
+ arg->peer_bw_rxnss_override |= BW_NSS_FWCONF_160(nss160);
+ break;
+ default:
+ break;
}
+
+ ath10k_dbg(ar, ATH10K_DBG_MAC, "mac vht peer %pM max_mpdu %d flags 0x%x peer_bw_rxnss_override 0x%x\n",
+ sta->addr, arg->peer_max_mpdu, arg->peer_flags,
+ arg->peer_bw_rxnss_override);
}
static void ath10k_peer_assoc_h_qos(struct ath10k *ar,
@@ -2743,9 +2765,9 @@ static int ath10k_peer_assoc_prepare(str
ath10k_peer_assoc_h_crypto(ar, vif, sta, arg);
ath10k_peer_assoc_h_rates(ar, vif, sta, arg);
ath10k_peer_assoc_h_ht(ar, vif, sta, arg);
+ ath10k_peer_assoc_h_phymode(ar, vif, sta, arg);
ath10k_peer_assoc_h_vht(ar, vif, sta, arg);
ath10k_peer_assoc_h_qos(ar, vif, sta, arg);
- ath10k_peer_assoc_h_phymode(ar, vif, sta, arg);
return 0;
}
--- a/drivers/net/wireless/ath/ath10k/wmi.c
+++ b/drivers/net/wireless/ath/ath10k/wmi.c
@@ -7552,12 +7552,7 @@ ath10k_wmi_peer_assoc_fill_10_4(struct a
struct wmi_10_4_peer_assoc_complete_cmd *cmd = buf;
ath10k_wmi_peer_assoc_fill_10_2(ar, buf, arg);
- if (arg->peer_bw_rxnss_override)
- cmd->peer_bw_rxnss_override =
- __cpu_to_le32((arg->peer_bw_rxnss_override - 1) |
- BIT(PEER_BW_RXNSS_OVERRIDE_OFFSET));
- else
- cmd->peer_bw_rxnss_override = 0;
+ cmd->peer_bw_rxnss_override = __cpu_to_le32(arg->peer_bw_rxnss_override);
}
static int
--- a/drivers/net/wireless/ath/ath10k/wmi.h
+++ b/drivers/net/wireless/ath/ath10k/wmi.h
@@ -6478,7 +6478,19 @@ struct wmi_10_2_peer_assoc_complete_cmd
__le32 info0; /* WMI_PEER_ASSOC_INFO0_ */
} __packed;
-#define PEER_BW_RXNSS_OVERRIDE_OFFSET 31
+#define BW_NSS_FWCONF_MAP_ENABLE BIT(31)
+#define BW_NSS_FWCONF_MAP_160MHZ_LSB (0)
+#define BW_NSS_FWCONF_MAP_160MHZ_MASK (0x00000007)
+#define BW_NSS_FWCONF_MAP_80_80MHZ_LSB (3)
+#define BW_NSS_FWCONF_MAP_80_80MHZ_MASK (0x00000038)
+#define BW_NSS_FWCONF_MAP_MASK (0x0000003F)
+
+#define GET_BW_NSS_FWCONF_160(x) (MS(x, BW_NSS_FWCONF_MAP_160MHZ) + 1)
+#define GET_BW_NSS_FWCONF_80_80(x) (MS(x, BW_NSS_FWCONF_MAP_80_80MHZ) + 1)
+
+/* Values defined to set 160 MHz Bandwidth NSS Mapping into FW*/
+#define BW_NSS_FWCONF_160(x) (BW_NSS_FWCONF_MAP_ENABLE | SM(x - 1, BW_NSS_FWCONF_MAP_160MHZ))
+#define BW_NSS_FWCONF_80_80(x) (BW_NSS_FWCONF_MAP_ENABLE | SM(x - 1, BW_NSS_FWCONF_MAP_80_80MHZ))
struct wmi_10_4_peer_assoc_complete_cmd {
struct wmi_10_2_peer_assoc_complete_cmd cmd;

View File

@ -1,53 +0,0 @@
From: Sebastian Gottschall <s.gottschall@dd-wrt.com>
starting with firmware 10.4.3.4.x series QCA changed the handling of the channel property band_center_freq1 and band_center_freq2 in vht160 operation mode
likelly for backward compatiblity with vht80 only capable clients.
this patch adjusts the handling to get vht160 to work again with official qca firmwares newer than 3.3
consider that this patch will not work with older firmwares anymore. to avoid undefined behaviour this we disable vht160 capability for outdated firmwares
Signed-off-by: Sebastian Gottschall <s.gottschall@dd-wrt.com>
v2: fix trailing whitespace issue and fix some typos within the commit note
---
drivers/net/wireless/ath/ath10k/mac.c | 7 -------
drivers/net/wireless/ath/ath10k/wmi.c | 11 ++++++++---
2 files changed, 8 insertions(+), 10 deletions(-)
--- a/drivers/net/wireless/ath/ath10k/mac.c
+++ b/drivers/net/wireless/ath/ath10k/mac.c
@@ -4578,13 +4578,6 @@ static struct ieee80211_sta_vht_cap ath1
vht_cap.cap |= val;
}
- /* Currently the firmware seems to be buggy, don't enable 80+80
- * mode until that's resolved.
- */
- if ((ar->vht_cap_info & IEEE80211_VHT_CAP_SHORT_GI_160) &&
- (ar->vht_cap_info & IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_MASK) == 0)
- vht_cap.cap |= IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160MHZ;
-
mcs_map = 0;
for (i = 0; i < 8; i++) {
if ((i < ar->num_rf_chains) && (ar->cfg_tx_chainmask & BIT(i)))
--- a/drivers/net/wireless/ath/ath10k/wmi.c
+++ b/drivers/net/wireless/ath/ath10k/wmi.c
@@ -1700,13 +1700,18 @@ void ath10k_wmi_put_wmi_channel(struct w
flags |= WMI_CHAN_FLAG_HT40_PLUS;
if (arg->chan_radar)
flags |= WMI_CHAN_FLAG_DFS;
-
+ ch->band_center_freq2 = 0;
ch->mhz = __cpu_to_le32(arg->freq);
ch->band_center_freq1 = __cpu_to_le32(arg->band_center_freq1);
if (arg->mode == MODE_11AC_VHT80_80)
ch->band_center_freq2 = __cpu_to_le32(arg->band_center_freq2);
- else
- ch->band_center_freq2 = 0;
+ if (arg->mode == MODE_11AC_VHT160) {
+ if (arg->freq < arg->band_center_freq1)
+ ch->band_center_freq1 = __cpu_to_le32(arg->band_center_freq1 - 40);
+ else
+ ch->band_center_freq1 = __cpu_to_le32(arg->band_center_freq1 + 40);
+ ch->band_center_freq2 = __cpu_to_le32(arg->band_center_freq1);
+ }
ch->min_power = arg->min_power;
ch->max_power = arg->max_power;
ch->reg_power = arg->max_reg_power;

View File

@ -85,7 +85,7 @@ v13:
create mode 100644 drivers/net/wireless/ath/ath10k/leds.h
--- a/drivers/net/wireless/ath/ath10k/Kconfig
+++ b/drivers/net/wireless/ath/ath10k/Kconfig
@@ -71,6 +71,16 @@ config ATH10K_DEBUGFS
@@ -70,6 +70,16 @@ config ATH10K_DEBUGFS
If unsure, say Y to make it easier to debug problems.
@ -124,7 +124,7 @@ v13:
WCN36XX=
--- a/drivers/net/wireless/ath/ath10k/core.c
+++ b/drivers/net/wireless/ath/ath10k/core.c
@@ -24,6 +24,7 @@
@@ -25,6 +25,7 @@
#include "testmode.h"
#include "wmi-ops.h"
#include "coredump.h"
@ -132,7 +132,7 @@ v13:
unsigned int ath10k_debug_mask;
EXPORT_SYMBOL(ath10k_debug_mask);
@@ -60,6 +61,7 @@ static const struct ath10k_hw_params ath
@@ -61,6 +62,7 @@ static const struct ath10k_hw_params ath
.dev_id = QCA988X_2_0_DEVICE_ID,
.bus = ATH10K_BUS_PCI,
.name = "qca988x hw2.0",
@ -148,7 +148,7 @@ v13:
.patch_load_addr = QCA9887_HW_1_0_PATCH_LOAD_ADDR,
.uart_pin = 7,
.cc_wraparound_type = ATH10K_HW_CC_WRAP_SHIFTED_ALL,
@@ -337,6 +340,7 @@ static const struct ath10k_hw_params ath
@@ -335,6 +338,7 @@ static const struct ath10k_hw_params ath
.dev_id = QCA99X0_2_0_DEVICE_ID,
.bus = ATH10K_BUS_PCI,
.name = "qca99x0 hw2.0",
@ -156,7 +156,7 @@ v13:
.patch_load_addr = QCA99X0_HW_2_0_PATCH_LOAD_ADDR,
.uart_pin = 7,
.otp_exe_param = 0x00000700,
@@ -378,6 +382,7 @@ static const struct ath10k_hw_params ath
@@ -375,6 +379,7 @@ static const struct ath10k_hw_params ath
.dev_id = QCA9984_1_0_DEVICE_ID,
.bus = ATH10K_BUS_PCI,
.name = "qca9984/qca9994 hw1.0",
@ -164,7 +164,7 @@ v13:
.patch_load_addr = QCA9984_HW_1_0_PATCH_LOAD_ADDR,
.uart_pin = 7,
.cc_wraparound_type = ATH10K_HW_CC_WRAP_SHIFTED_EACH,
@@ -426,6 +431,7 @@ static const struct ath10k_hw_params ath
@@ -422,6 +427,7 @@ static const struct ath10k_hw_params ath
.dev_id = QCA9888_2_0_DEVICE_ID,
.bus = ATH10K_BUS_PCI,
.name = "qca9888 hw2.0",
@ -172,7 +172,7 @@ v13:
.patch_load_addr = QCA9888_HW_2_0_PATCH_LOAD_ADDR,
.uart_pin = 7,
.cc_wraparound_type = ATH10K_HW_CC_WRAP_SHIFTED_EACH,
@@ -2791,6 +2797,10 @@ int ath10k_core_start(struct ath10k *ar,
@@ -2904,6 +2910,10 @@ int ath10k_core_start(struct ath10k *ar,
goto err_hif_stop;
}
@ -183,7 +183,7 @@ v13:
return 0;
err_hif_stop:
@@ -3047,9 +3057,18 @@ static void ath10k_core_register_work(st
@@ -3162,9 +3172,18 @@ static void ath10k_core_register_work(st
goto err_spectral_destroy;
}
@ -202,7 +202,7 @@ v13:
err_spectral_destroy:
ath10k_spectral_destroy(ar);
err_debug_destroy:
@@ -3095,6 +3114,8 @@ void ath10k_core_unregister(struct ath10
@@ -3210,6 +3229,8 @@ void ath10k_core_unregister(struct ath10
if (!test_bit(ATH10K_FLAG_CORE_REGISTERED, &ar->dev_flags))
return;
@ -221,7 +221,7 @@ v13:
#include "htt.h"
#include "htc.h"
@@ -1170,6 +1171,13 @@ struct ath10k {
@@ -1237,6 +1238,13 @@ struct ath10k {
} testmode;
struct {
@ -233,11 +233,11 @@ v13:
+
+ struct {
/* protected by data_lock */
u32 rx_crc_err_drop;
u32 fw_crash_counter;
u32 fw_warm_reset_counter;
--- a/drivers/net/wireless/ath/ath10k/hw.h
+++ b/drivers/net/wireless/ath/ath10k/hw.h
@@ -514,6 +514,7 @@ struct ath10k_hw_params {
@@ -517,6 +517,7 @@ struct ath10k_hw_params {
const char *name;
u32 patch_load_addr;
int uart_pin;
@ -397,7 +397,7 @@ v13:
+#endif /* _LEDS_H_ */
--- a/drivers/net/wireless/ath/ath10k/mac.c
+++ b/drivers/net/wireless/ath/ath10k/mac.c
@@ -23,6 +23,7 @@
@@ -24,6 +24,7 @@
#include "wmi-tlv.h"
#include "wmi-ops.h"
#include "wow.h"
@ -407,10 +407,10 @@ v13:
/* Rates */
--- a/drivers/net/wireless/ath/ath10k/wmi-ops.h
+++ b/drivers/net/wireless/ath/ath10k/wmi-ops.h
@@ -217,7 +217,10 @@ struct wmi_ops {
struct sk_buff *(*gen_bb_timing)
(struct ath10k *ar,
@@ -226,7 +226,10 @@ struct wmi_ops {
const struct wmi_bb_timing_cfg_arg *arg);
struct sk_buff *(*gen_per_peer_per_tid_cfg)(struct ath10k *ar,
const struct wmi_per_peer_per_tid_cfg_arg *arg);
+ struct sk_buff *(*gen_gpio_config)(struct ath10k *ar, u32 gpio_num,
+ u32 input, u32 pull_type, u32 intr_mode);
@ -418,7 +418,7 @@ v13:
};
int ath10k_wmi_cmd_send(struct ath10k *ar, struct sk_buff *skb, u32 cmd_id);
@@ -1090,6 +1093,35 @@ ath10k_wmi_force_fw_hang(struct ath10k *
@@ -1122,6 +1125,35 @@ ath10k_wmi_force_fw_hang(struct ath10k *
return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->force_fw_hang_cmdid);
}
@ -456,7 +456,7 @@ v13:
{
--- a/drivers/net/wireless/ath/ath10k/wmi-tlv.c
+++ b/drivers/net/wireless/ath/ath10k/wmi-tlv.c
@@ -4382,6 +4382,8 @@ static const struct wmi_ops wmi_tlv_ops
@@ -4585,6 +4585,8 @@ static const struct wmi_ops wmi_tlv_ops
.gen_echo = ath10k_wmi_tlv_op_gen_echo,
.gen_vdev_spectral_conf = ath10k_wmi_tlv_op_gen_vdev_spectral_conf,
.gen_vdev_spectral_enable = ath10k_wmi_tlv_op_gen_vdev_spectral_enable,
@ -467,7 +467,7 @@ v13:
static const struct wmi_peer_flags_map wmi_tlv_peer_flags_map = {
--- a/drivers/net/wireless/ath/ath10k/wmi.c
+++ b/drivers/net/wireless/ath/ath10k/wmi.c
@@ -7372,6 +7372,49 @@ ath10k_wmi_op_gen_peer_set_param(struct
@@ -7468,6 +7468,49 @@ ath10k_wmi_op_gen_peer_set_param(struct
return skb;
}
@ -517,7 +517,7 @@ v13:
static struct sk_buff *
ath10k_wmi_op_gen_set_psmode(struct ath10k *ar, u32 vdev_id,
enum wmi_sta_ps_mode psmode)
@@ -9029,6 +9072,9 @@ static const struct wmi_ops wmi_ops = {
@@ -9156,6 +9199,9 @@ static const struct wmi_ops wmi_ops = {
.fw_stats_fill = ath10k_wmi_main_op_fw_stats_fill,
.get_vdev_subtype = ath10k_wmi_op_get_vdev_subtype,
.gen_echo = ath10k_wmi_op_gen_echo,
@ -527,7 +527,7 @@ v13:
/* .gen_bcn_tmpl not implemented */
/* .gen_prb_tmpl not implemented */
/* .gen_p2p_go_bcn_ie not implemented */
@@ -9099,6 +9145,8 @@ static const struct wmi_ops wmi_10_1_ops
@@ -9226,6 +9272,8 @@ static const struct wmi_ops wmi_10_1_ops
.fw_stats_fill = ath10k_wmi_10x_op_fw_stats_fill,
.get_vdev_subtype = ath10k_wmi_op_get_vdev_subtype,
.gen_echo = ath10k_wmi_op_gen_echo,
@ -536,7 +536,7 @@ v13:
/* .gen_bcn_tmpl not implemented */
/* .gen_prb_tmpl not implemented */
/* .gen_p2p_go_bcn_ie not implemented */
@@ -9171,6 +9219,8 @@ static const struct wmi_ops wmi_10_2_ops
@@ -9298,6 +9346,8 @@ static const struct wmi_ops wmi_10_2_ops
.gen_delba_send = ath10k_wmi_op_gen_delba_send,
.fw_stats_fill = ath10k_wmi_10x_op_fw_stats_fill,
.get_vdev_subtype = ath10k_wmi_op_get_vdev_subtype,
@ -545,7 +545,7 @@ v13:
/* .gen_pdev_enable_adaptive_cca not implemented */
};
@@ -9242,6 +9292,8 @@ static const struct wmi_ops wmi_10_2_4_o
@@ -9369,6 +9419,8 @@ static const struct wmi_ops wmi_10_2_4_o
ath10k_wmi_op_gen_pdev_enable_adaptive_cca,
.get_vdev_subtype = ath10k_wmi_10_2_4_op_get_vdev_subtype,
.gen_bb_timing = ath10k_wmi_10_2_4_op_gen_bb_timing,
@ -554,7 +554,7 @@ v13:
/* .gen_bcn_tmpl not implemented */
/* .gen_prb_tmpl not implemented */
/* .gen_p2p_go_bcn_ie not implemented */
@@ -9322,6 +9374,8 @@ static const struct wmi_ops wmi_10_4_ops
@@ -9450,6 +9502,8 @@ static const struct wmi_ops wmi_10_4_ops
.gen_pdev_bss_chan_info_req = ath10k_wmi_10_2_op_gen_pdev_bss_chan_info,
.gen_echo = ath10k_wmi_op_gen_echo,
.gen_pdev_get_tpc_config = ath10k_wmi_10_2_4_op_gen_pdev_get_tpc_config,
@ -565,7 +565,7 @@ v13:
int ath10k_wmi_attach(struct ath10k *ar)
--- a/drivers/net/wireless/ath/ath10k/wmi.h
+++ b/drivers/net/wireless/ath/ath10k/wmi.h
@@ -3005,6 +3005,41 @@ enum wmi_10_4_feature_mask {
@@ -3027,6 +3027,41 @@ enum wmi_10_4_feature_mask {
};

View File

@ -16,16 +16,16 @@ Signed-off-by: Mathias Kresin <dev@kresin.me>
--- a/drivers/net/wireless/ath/ath10k/core.h
+++ b/drivers/net/wireless/ath/ath10k/core.h
@@ -1219,6 +1219,10 @@ struct ath10k {
struct ath10k_bus_params bus_param;
struct completion peer_delete_done;
@@ -1290,6 +1290,10 @@ struct ath10k {
bool coex_support;
int coex_gpio_pin;
+#ifdef CPTCFG_MAC80211_LEDS
+ const char *led_default_trigger;
+#endif
+
/* must be last */
u8 drv_priv[0] __aligned(sizeof(void *));
u8 drv_priv[] __aligned(sizeof(void *));
};
--- a/drivers/net/wireless/ath/ath10k/leds.c
+++ b/drivers/net/wireless/ath/ath10k/leds.c
@ -42,7 +42,7 @@ Signed-off-by: Mathias Kresin <dev@kresin.me>
if (ret)
--- a/drivers/net/wireless/ath/ath10k/mac.c
+++ b/drivers/net/wireless/ath/ath10k/mac.c
@@ -9035,7 +9035,7 @@ int ath10k_mac_register(struct ath10k *a
@@ -10079,7 +10079,7 @@ int ath10k_mac_register(struct ath10k *a
ar->hw->weight_multiplier = ATH10K_AIRTIME_WEIGHT_MULTIPLIER;
#ifdef CPTCFG_MAC80211_LEDS

View File

@ -20,7 +20,7 @@ Forwarded: https://patchwork.kernel.org/patch/10986723/
--- a/drivers/net/wireless/ath/ath10k/mac.c
+++ b/drivers/net/wireless/ath/ath10k/mac.c
@@ -1041,7 +1041,7 @@ static int ath10k_monitor_vdev_start(str
@@ -1038,7 +1038,7 @@ static int ath10k_monitor_vdev_start(str
arg.channel.min_power = 0;
arg.channel.max_power = channel->max_power * 2;
arg.channel.max_reg_power = channel->max_reg_power * 2;
@ -29,7 +29,7 @@ Forwarded: https://patchwork.kernel.org/patch/10986723/
reinit_completion(&ar->vdev_setup_done);
reinit_completion(&ar->vdev_delete_done);
@@ -1487,7 +1487,7 @@ static int ath10k_vdev_start_restart(str
@@ -1484,7 +1484,7 @@ static int ath10k_vdev_start_restart(str
arg.channel.min_power = 0;
arg.channel.max_power = chandef->chan->max_power * 2;
arg.channel.max_reg_power = chandef->chan->max_reg_power * 2;
@ -38,7 +38,7 @@ Forwarded: https://patchwork.kernel.org/patch/10986723/
if (arvif->vdev_type == WMI_VDEV_TYPE_AP) {
arg.ssid = arvif->u.ap.ssid;
@@ -3168,7 +3168,7 @@ static int ath10k_update_channel_list(st
@@ -3255,7 +3255,7 @@ static int ath10k_update_channel_list(st
ch->min_power = 0;
ch->max_power = channel->max_power * 2;
ch->max_reg_power = channel->max_reg_power * 2;

View File

@ -28,7 +28,7 @@ Forwarded: no
--- a/drivers/net/wireless/ath/ath10k/mac.c
+++ b/drivers/net/wireless/ath/ath10k/mac.c
@@ -1009,6 +1009,40 @@ static inline int ath10k_vdev_setup_sync
@@ -1006,6 +1006,40 @@ static inline int ath10k_vdev_setup_sync
return ar->last_wmi_vdev_start_status;
}
@ -69,7 +69,7 @@ Forwarded: no
static int ath10k_monitor_vdev_start(struct ath10k *ar, int vdev_id)
{
struct cfg80211_chan_def *chandef = NULL;
@@ -1041,7 +1075,8 @@ static int ath10k_monitor_vdev_start(str
@@ -1038,7 +1072,8 @@ static int ath10k_monitor_vdev_start(str
arg.channel.min_power = 0;
arg.channel.max_power = channel->max_power * 2;
arg.channel.max_reg_power = channel->max_reg_power * 2;
@ -79,7 +79,7 @@ Forwarded: no
reinit_completion(&ar->vdev_setup_done);
reinit_completion(&ar->vdev_delete_done);
@@ -1487,7 +1522,8 @@ static int ath10k_vdev_start_restart(str
@@ -1484,7 +1519,8 @@ static int ath10k_vdev_start_restart(str
arg.channel.min_power = 0;
arg.channel.max_power = chandef->chan->max_power * 2;
arg.channel.max_reg_power = chandef->chan->max_reg_power * 2;
@ -89,7 +89,7 @@ Forwarded: no
if (arvif->vdev_type == WMI_VDEV_TYPE_AP) {
arg.ssid = arvif->u.ap.ssid;
@@ -3168,7 +3204,8 @@ static int ath10k_update_channel_list(st
@@ -3255,7 +3291,8 @@ static int ath10k_update_channel_list(st
ch->min_power = 0;
ch->max_power = channel->max_power * 2;
ch->max_reg_power = channel->max_reg_power * 2;

View File

@ -1,28 +0,0 @@
From 1524cbf3621576c639405e7aabeac415f9617c8d Mon Sep 17 00:00:00 2001
From: Adrian Ratiu <adrian.ratiu@collabora.com>
Date: Wed, 25 Sep 2019 16:44:57 +0300
Subject: [PATCH] brcmfmac: don't WARN when there are no requests
When n_reqs == 0 there is nothing to do so it doesn't make sense to
search for requests and issue a warning because none is found.
Signed-off-by: Martyn Welch <martyn.welch@collabora.com>
Signed-off-by: Adrian Ratiu <adrian.ratiu@collabora.com>
Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
---
drivers/net/wireless/broadcom/brcm80211/brcmfmac/pno.c | 4 ++++
1 file changed, 4 insertions(+)
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pno.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pno.c
@@ -57,6 +57,10 @@ static int brcmf_pno_remove_request(stru
mutex_lock(&pi->req_lock);
+ /* Nothing to do if we have no requests */
+ if (pi->n_reqs == 0)
+ goto done;
+
/* find request */
for (i = 0; i < pi->n_reqs; i++) {
if (pi->reqs[i]->reqid == reqid)

View File

@ -1,109 +0,0 @@
From e0ae4bac22effbd644add326f658a3aeeb8d45ee Mon Sep 17 00:00:00 2001
From: Adrian Ratiu <adrian.ratiu@collabora.com>
Date: Wed, 25 Sep 2019 16:44:58 +0300
Subject: [PATCH] brcmfmac: fix suspend/resume when power is cut off
brcmfmac assumed the wifi device always remains powered on and thus
hardcoded the MMC_PM_KEEP_POWER flag expecting the wifi device to
remain on even during suspend/resume cycles.
This is not always the case, some appliances cut power to everything
connected via SDIO for efficiency reasons and this leads to wifi not
being usable after coming out of suspend because the device was not
correctly reinitialized.
So we check for the keep_power capability and if it's not present then
we remove the device and probe it again during resume to mirror what's
happening in hardware and ensure correct reinitialization in the case
when MMC_PM_KEEP_POWER is not supported.
Suggested-by: Gustavo Padovan <gustavo.padovan@collabora.com>
Signed-off-by: Adrian Ratiu <adrian.ratiu@collabora.com>
Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
---
.../broadcom/brcm80211/brcmfmac/bcmsdh.c | 53 ++++++++++++++-----
1 file changed, 39 insertions(+), 14 deletions(-)
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcmsdh.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcmsdh.c
@@ -1108,7 +1108,8 @@ static int brcmf_ops_sdio_suspend(struct
struct sdio_func *func;
struct brcmf_bus *bus_if;
struct brcmf_sdio_dev *sdiodev;
- mmc_pm_flag_t sdio_flags;
+ mmc_pm_flag_t pm_caps, sdio_flags;
+ int ret = 0;
func = container_of(dev, struct sdio_func, dev);
brcmf_dbg(SDIO, "Enter: F%d\n", func->num);
@@ -1119,19 +1120,33 @@ static int brcmf_ops_sdio_suspend(struct
bus_if = dev_get_drvdata(dev);
sdiodev = bus_if->bus_priv.sdio;
- brcmf_sdiod_freezer_on(sdiodev);
- brcmf_sdio_wd_timer(sdiodev->bus, 0);
+ pm_caps = sdio_get_host_pm_caps(func);
- sdio_flags = MMC_PM_KEEP_POWER;
- if (sdiodev->wowl_enabled) {
- if (sdiodev->settings->bus.sdio.oob_irq_supported)
- enable_irq_wake(sdiodev->settings->bus.sdio.oob_irq_nr);
- else
- sdio_flags |= MMC_PM_WAKE_SDIO_IRQ;
+ if (pm_caps & MMC_PM_KEEP_POWER) {
+ /* preserve card power during suspend */
+ brcmf_sdiod_freezer_on(sdiodev);
+ brcmf_sdio_wd_timer(sdiodev->bus, 0);
+
+ sdio_flags = MMC_PM_KEEP_POWER;
+ if (sdiodev->wowl_enabled) {
+ if (sdiodev->settings->bus.sdio.oob_irq_supported)
+ enable_irq_wake(sdiodev->settings->bus.sdio.oob_irq_nr);
+ else
+ sdio_flags |= MMC_PM_WAKE_SDIO_IRQ;
+ }
+
+ if (sdio_set_host_pm_flags(sdiodev->func1, sdio_flags))
+ brcmf_err("Failed to set pm_flags %x\n", sdio_flags);
+
+ } else {
+ /* power will be cut so remove device, probe again in resume */
+ brcmf_sdiod_intr_unregister(sdiodev);
+ ret = brcmf_sdiod_remove(sdiodev);
+ if (ret)
+ brcmf_err("Failed to remove device on suspend\n");
}
- if (sdio_set_host_pm_flags(sdiodev->func1, sdio_flags))
- brcmf_err("Failed to set pm_flags %x\n", sdio_flags);
- return 0;
+
+ return ret;
}
static int brcmf_ops_sdio_resume(struct device *dev)
@@ -1139,13 +1154,23 @@ static int brcmf_ops_sdio_resume(struct
struct brcmf_bus *bus_if = dev_get_drvdata(dev);
struct brcmf_sdio_dev *sdiodev = bus_if->bus_priv.sdio;
struct sdio_func *func = container_of(dev, struct sdio_func, dev);
+ mmc_pm_flag_t pm_caps = sdio_get_host_pm_caps(func);
+ int ret = 0;
brcmf_dbg(SDIO, "Enter: F%d\n", func->num);
if (func->num != 2)
return 0;
- brcmf_sdiod_freezer_off(sdiodev);
- return 0;
+ if (!(pm_caps & MMC_PM_KEEP_POWER)) {
+ /* bus was powered off and device removed, probe again */
+ ret = brcmf_sdiod_probe(sdiodev);
+ if (ret)
+ brcmf_err("Failed to probe device on resume\n");
+ } else {
+ brcmf_sdiod_freezer_off(sdiodev);
+ }
+
+ return ret;
}
static const struct dev_pm_ops brcmf_sdio_pm_ops = {

View File

@ -1,58 +0,0 @@
From 7af496b9eb0433bc4cb478c9a46f85509cdb5541 Mon Sep 17 00:00:00 2001
From: zhengbin <zhengbin13@huawei.com>
Date: Sat, 16 Nov 2019 15:22:47 +0800
Subject: [PATCH] brcmfmac: remove set but not used variable
'mpnum','nsp','nmp'
Fixes gcc '-Wunused-but-set-variable' warning:
drivers/net/wireless/broadcom/brcm80211/brcmfmac/chip.c: In function brcmf_chip_dmp_get_regaddr:
drivers/net/wireless/broadcom/brcm80211/brcmfmac/chip.c:790:5: warning: variable mpnum set but not used [-Wunused-but-set-variable]
drivers/net/wireless/broadcom/brcm80211/brcmfmac/chip.c: In function brcmf_chip_dmp_erom_scan:
drivers/net/wireless/broadcom/brcm80211/brcmfmac/chip.c:866:10: warning: variable nsp set but not used [-Wunused-but-set-variable]
drivers/net/wireless/broadcom/brcm80211/brcmfmac/chip.c: In function brcmf_chip_dmp_erom_scan:
drivers/net/wireless/broadcom/brcm80211/brcmfmac/chip.c:866:5: warning: variable nmp set but not used [-Wunused-but-set-variable]
Reported-by: Hulk Robot <hulkci@huawei.com>
Signed-off-by: zhengbin <zhengbin13@huawei.com>
Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
---
drivers/net/wireless/broadcom/brcm80211/brcmfmac/chip.c | 6 +-----
1 file changed, 1 insertion(+), 5 deletions(-)
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/chip.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/chip.c
@@ -778,7 +778,6 @@ static int brcmf_chip_dmp_get_regaddr(st
{
u8 desc;
u32 val, szdesc;
- u8 mpnum = 0;
u8 stype, sztype, wraptype;
*regbase = 0;
@@ -786,7 +785,6 @@ static int brcmf_chip_dmp_get_regaddr(st
val = brcmf_chip_dmp_get_desc(ci, eromaddr, &desc);
if (desc == DMP_DESC_MASTER_PORT) {
- mpnum = (val & DMP_MASTER_PORT_NUM) >> DMP_MASTER_PORT_NUM_S;
wraptype = DMP_SLAVE_TYPE_MWRAP;
} else if (desc == DMP_DESC_ADDRESS) {
/* revert erom address */
@@ -854,7 +852,7 @@ int brcmf_chip_dmp_erom_scan(struct brcm
u8 desc_type = 0;
u32 val;
u16 id;
- u8 nmp, nsp, nmw, nsw, rev;
+ u8 nmw, nsw, rev;
u32 base, wrap;
int err;
@@ -880,8 +878,6 @@ int brcmf_chip_dmp_erom_scan(struct brcm
return -EFAULT;
/* only look at cores with master port(s) */
- nmp = (val & DMP_COMP_NUM_MPORT) >> DMP_COMP_NUM_MPORT_S;
- nsp = (val & DMP_COMP_NUM_SPORT) >> DMP_COMP_NUM_SPORT_S;
nmw = (val & DMP_COMP_NUM_MWRAP) >> DMP_COMP_NUM_MWRAP_S;
nsw = (val & DMP_COMP_NUM_SWRAP) >> DMP_COMP_NUM_SWRAP_S;
rev = (val & DMP_COMP_REVISION) >> DMP_COMP_REVISION_S;

View File

@ -1,29 +0,0 @@
From 8d9627b05b2c33e4468e65739eb7caf9c3f274d8 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= <rafal@milecki.pl>
Date: Tue, 10 Dec 2019 12:35:55 +0100
Subject: [PATCH] brcmfmac: set interface carrier to off by default
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
It's important as brcmfmac creates one main interface for each PHY and
doesn't allow deleting it. Not setting carrier could result in other
subsystems misbehaving (e.g. LEDs "netdev" trigger turning LED on).
Signed-off-by: Rafał Miłecki <rafal@milecki.pl>
Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
---
drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c | 2 ++
1 file changed, 2 insertions(+)
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c
@@ -678,6 +678,8 @@ int brcmf_net_attach(struct brcmf_if *if
goto fail;
}
+ netif_carrier_off(ndev);
+
netdev_set_priv_destructor(ndev, brcmf_cfg80211_free_netdev);
brcmf_dbg(INFO, "%s: Broadcom Dongle Host Driver\n", ndev->name);
return 0;

View File

@ -1,121 +0,0 @@
From 1b8d2e0a9e4221b99eea375c079507ce8ef655f5 Mon Sep 17 00:00:00 2001
From: Wright Feng <wright.feng@cypress.com>
Date: Thu, 12 Dec 2019 00:52:45 +0100
Subject: [PATCH 1/7] brcmfmac: reset two D11 cores if chip has two D11 cores
There are two D11 cores in RSDB chips like 4359. We have to reset two
D11 cores simutaneously before firmware download, or the firmware may
not be initialized correctly and cause "fw initialized failed" error.
Signed-off-by: Wright Feng <wright.feng@cypress.com>
Signed-off-by: Soeren Moch <smoch@web.de>
Reviewed-by: Chi-Hsien Lin <chi-hsien.lin@cypress.com>
Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
---
.../broadcom/brcm80211/brcmfmac/chip.c | 50 +++++++++++++++++++
.../broadcom/brcm80211/brcmfmac/chip.h | 1 +
.../broadcom/brcm80211/brcmfmac/pcie.c | 2 +-
3 files changed, 52 insertions(+), 1 deletion(-)
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/chip.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/chip.c
@@ -433,11 +433,25 @@ static void brcmf_chip_ai_resetcore(stru
{
struct brcmf_chip_priv *ci;
int count;
+ struct brcmf_core *d11core2 = NULL;
+ struct brcmf_core_priv *d11priv2 = NULL;
ci = core->chip;
+ /* special handle two D11 cores reset */
+ if (core->pub.id == BCMA_CORE_80211) {
+ d11core2 = brcmf_chip_get_d11core(&ci->pub, 1);
+ if (d11core2) {
+ brcmf_dbg(INFO, "found two d11 cores, reset both\n");
+ d11priv2 = container_of(d11core2,
+ struct brcmf_core_priv, pub);
+ }
+ }
+
/* must disable first to work for arbitrary current core state */
brcmf_chip_ai_coredisable(core, prereset, reset);
+ if (d11priv2)
+ brcmf_chip_ai_coredisable(d11priv2, prereset, reset);
count = 0;
while (ci->ops->read32(ci->ctx, core->wrapbase + BCMA_RESET_CTL) &
@@ -449,9 +463,30 @@ static void brcmf_chip_ai_resetcore(stru
usleep_range(40, 60);
}
+ if (d11priv2) {
+ count = 0;
+ while (ci->ops->read32(ci->ctx,
+ d11priv2->wrapbase + BCMA_RESET_CTL) &
+ BCMA_RESET_CTL_RESET) {
+ ci->ops->write32(ci->ctx,
+ d11priv2->wrapbase + BCMA_RESET_CTL,
+ 0);
+ count++;
+ if (count > 50)
+ break;
+ usleep_range(40, 60);
+ }
+ }
+
ci->ops->write32(ci->ctx, core->wrapbase + BCMA_IOCTL,
postreset | BCMA_IOCTL_CLK);
ci->ops->read32(ci->ctx, core->wrapbase + BCMA_IOCTL);
+
+ if (d11priv2) {
+ ci->ops->write32(ci->ctx, d11priv2->wrapbase + BCMA_IOCTL,
+ postreset | BCMA_IOCTL_CLK);
+ ci->ops->read32(ci->ctx, d11priv2->wrapbase + BCMA_IOCTL);
+ }
}
char *brcmf_chip_name(u32 id, u32 rev, char *buf, uint len)
@@ -1109,6 +1144,21 @@ void brcmf_chip_detach(struct brcmf_chip
kfree(chip);
}
+struct brcmf_core *brcmf_chip_get_d11core(struct brcmf_chip *pub, u8 unit)
+{
+ struct brcmf_chip_priv *chip;
+ struct brcmf_core_priv *core;
+
+ chip = container_of(pub, struct brcmf_chip_priv, pub);
+ list_for_each_entry(core, &chip->cores, list) {
+ if (core->pub.id == BCMA_CORE_80211) {
+ if (unit-- == 0)
+ return &core->pub;
+ }
+ }
+ return NULL;
+}
+
struct brcmf_core *brcmf_chip_get_core(struct brcmf_chip *pub, u16 coreid)
{
struct brcmf_chip_priv *chip;
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/chip.h
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/chip.h
@@ -74,6 +74,7 @@ struct brcmf_chip *brcmf_chip_attach(voi
const struct brcmf_buscore_ops *ops);
void brcmf_chip_detach(struct brcmf_chip *chip);
struct brcmf_core *brcmf_chip_get_core(struct brcmf_chip *chip, u16 coreid);
+struct brcmf_core *brcmf_chip_get_d11core(struct brcmf_chip *pub, u8 unit);
struct brcmf_core *brcmf_chip_get_chipcommon(struct brcmf_chip *chip);
struct brcmf_core *brcmf_chip_get_pmu(struct brcmf_chip *pub);
bool brcmf_chip_iscoreup(struct brcmf_core *core);
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c
@@ -78,7 +78,7 @@ static const struct brcmf_firmware_mappi
BRCMF_FW_ENTRY(BRCM_CC_4371_CHIP_ID, 0xFFFFFFFF, 4371),
};
-#define BRCMF_PCIE_FW_UP_TIMEOUT 2000 /* msec */
+#define BRCMF_PCIE_FW_UP_TIMEOUT 5000 /* msec */
#define BRCMF_PCIE_REG_MAP_SIZE (32 * 1024)

View File

@ -1,79 +0,0 @@
From 172f6854551d48d1c9530f84513b421db944e714 Mon Sep 17 00:00:00 2001
From: Chung-Hsien Hsu <stanley.hsu@cypress.com>
Date: Thu, 12 Dec 2019 00:52:46 +0100
Subject: [PATCH 2/7] brcmfmac: set F2 blocksize and watermark for 4359
Set F2 blocksize to 256 bytes and watermark to 0x40 for 4359. Also
enable and configure F1 MesBusyCtrl. It fixes DMA error while having
UDP bi-directional traffic.
Signed-off-by: Chung-Hsien Hsu <stanley.hsu@cypress.com>
[slightly adapted for rebase on mainline linux]
Signed-off-by: Soeren Moch <smoch@web.de>
Reviewed-by: Chi-Hsien Lin <chi-hsien.lin@cypress.com>
Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
---
.../wireless/broadcom/brcm80211/brcmfmac/bcmsdh.c | 6 +++++-
.../wireless/broadcom/brcm80211/brcmfmac/sdio.c | 15 +++++++++++++++
2 files changed, 20 insertions(+), 1 deletion(-)
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcmsdh.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcmsdh.c
@@ -43,6 +43,7 @@
#define SDIO_FUNC1_BLOCKSIZE 64
#define SDIO_FUNC2_BLOCKSIZE 512
+#define SDIO_4359_FUNC2_BLOCKSIZE 256
/* Maximum milliseconds to wait for F2 to come up */
#define SDIO_WAIT_F2RDY 3000
@@ -903,6 +904,7 @@ static void brcmf_sdiod_host_fixup(struc
static int brcmf_sdiod_probe(struct brcmf_sdio_dev *sdiodev)
{
int ret = 0;
+ unsigned int f2_blksz = SDIO_FUNC2_BLOCKSIZE;
sdio_claim_host(sdiodev->func1);
@@ -912,7 +914,9 @@ static int brcmf_sdiod_probe(struct brcm
sdio_release_host(sdiodev->func1);
goto out;
}
- ret = sdio_set_block_size(sdiodev->func2, SDIO_FUNC2_BLOCKSIZE);
+ if (sdiodev->func2->device == SDIO_DEVICE_ID_BROADCOM_4359)
+ f2_blksz = SDIO_4359_FUNC2_BLOCKSIZE;
+ ret = sdio_set_block_size(sdiodev->func2, f2_blksz);
if (ret) {
brcmf_err("Failed to set F2 blocksize\n");
sdio_release_host(sdiodev->func1);
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c
@@ -42,6 +42,8 @@
#define DEFAULT_F2_WATERMARK 0x8
#define CY_4373_F2_WATERMARK 0x40
#define CY_43012_F2_WATERMARK 0x60
+#define CY_4359_F2_WATERMARK 0x40
+#define CY_4359_F1_MESBUSYCTRL (CY_4359_F2_WATERMARK | SBSDIO_MESBUSYCTRL_ENAB)
#ifdef DEBUG
@@ -4208,6 +4210,19 @@ static void brcmf_sdio_firmware_callback
brcmf_sdiod_writeb(sdiod, SBSDIO_DEVICE_CTL, devctl,
&err);
break;
+ case SDIO_DEVICE_ID_BROADCOM_4359:
+ brcmf_dbg(INFO, "set F2 watermark to 0x%x*4 bytes\n",
+ CY_4359_F2_WATERMARK);
+ brcmf_sdiod_writeb(sdiod, SBSDIO_WATERMARK,
+ CY_4359_F2_WATERMARK, &err);
+ devctl = brcmf_sdiod_readb(sdiod, SBSDIO_DEVICE_CTL,
+ &err);
+ devctl |= SBSDIO_DEVCTL_F2WM_ENAB;
+ brcmf_sdiod_writeb(sdiod, SBSDIO_DEVICE_CTL, devctl,
+ &err);
+ brcmf_sdiod_writeb(sdiod, SBSDIO_FUNC1_MESBUSYCTRL,
+ CY_4359_F1_MESBUSYCTRL, &err);
+ break;
default:
brcmf_sdiod_writeb(sdiod, SBSDIO_WATERMARK,
DEFAULT_F2_WATERMARK, &err);

View File

@ -1,34 +0,0 @@
From 6647274ed995a172369cb04754eb5f8b85f68f6d Mon Sep 17 00:00:00 2001
From: Soeren Moch <smoch@web.de>
Date: Thu, 12 Dec 2019 00:52:47 +0100
Subject: [PATCH 3/7] brcmfmac: fix rambase for 4359/9
Newer 4359 chip revisions need a different rambase address.
This fixes firmware download on such devices which fails otherwise.
Signed-off-by: Soeren Moch <smoch@web.de>
Acked-by: Chi-Hsien Lin <chi-hsien.lin@cypress.com>
Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
---
drivers/net/wireless/broadcom/brcm80211/brcmfmac/chip.c | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/chip.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/chip.c
@@ -712,7 +712,6 @@ static u32 brcmf_chip_tcm_rambase(struct
case BRCM_CC_43569_CHIP_ID:
case BRCM_CC_43570_CHIP_ID:
case BRCM_CC_4358_CHIP_ID:
- case BRCM_CC_4359_CHIP_ID:
case BRCM_CC_43602_CHIP_ID:
case BRCM_CC_4371_CHIP_ID:
return 0x180000;
@@ -722,6 +721,8 @@ static u32 brcmf_chip_tcm_rambase(struct
case BRCM_CC_4366_CHIP_ID:
case BRCM_CC_43664_CHIP_ID:
return 0x200000;
+ case BRCM_CC_4359_CHIP_ID:
+ return (ci->pub.chiprev < 9) ? 0x180000 : 0x160000;
case CY_CC_4373_CHIP_ID:
return 0x160000;
default:

View File

@ -1,42 +0,0 @@
From c12c8913d79c49ceccb38f42714d25b783833758 Mon Sep 17 00:00:00 2001
From: Soeren Moch <smoch@web.de>
Date: Thu, 12 Dec 2019 00:52:48 +0100
Subject: [PATCH 4/7] brcmfmac: make errors when setting roaming parameters
non-fatal
4359 dongles do not support setting roaming parameters (error -52).
Do not fail the 80211 configuration in this case.
Signed-off-by: Soeren Moch <smoch@web.de>
Acked-by: Chi-Hsien Lin <chi-hsien.lin@cypress.com>
Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
---
.../wireless/broadcom/brcm80211/brcmfmac/cfg80211.c | 10 ++++------
1 file changed, 4 insertions(+), 6 deletions(-)
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c
@@ -5944,19 +5944,17 @@ static s32 brcmf_dongle_roam(struct brcm
roamtrigger[1] = cpu_to_le32(BRCM_BAND_ALL);
err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SET_ROAM_TRIGGER,
(void *)roamtrigger, sizeof(roamtrigger));
- if (err) {
+ if (err)
bphy_err(drvr, "WLC_SET_ROAM_TRIGGER error (%d)\n", err);
- goto roam_setup_done;
- }
roam_delta[0] = cpu_to_le32(WL_ROAM_DELTA);
roam_delta[1] = cpu_to_le32(BRCM_BAND_ALL);
err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SET_ROAM_DELTA,
(void *)roam_delta, sizeof(roam_delta));
- if (err) {
+ if (err)
bphy_err(drvr, "WLC_SET_ROAM_DELTA error (%d)\n", err);
- goto roam_setup_done;
- }
+
+ return 0;
roam_setup_done:
return err;

View File

@ -1,75 +0,0 @@
From d4aef159394d5940bd7158ab789969dab82f7c76 Mon Sep 17 00:00:00 2001
From: Soeren Moch <smoch@web.de>
Date: Thu, 12 Dec 2019 00:52:49 +0100
Subject: [PATCH 5/7] brcmfmac: add support for BCM4359 SDIO chipset
BCM4359 is a 2x2 802.11 abgn+ac Dual-Band HT80 combo chip and it
supports Real Simultaneous Dual Band feature.
Based on a similar patch by: Wright Feng <wright.feng@cypress.com>
Signed-off-by: Soeren Moch <smoch@web.de>
Acked-by: Chi-Hsien Lin <chi-hsien.lin@cypress.com>
Acked-by: Ulf Hansson <ulf.hansson@linaro.org>
Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
---
drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcmsdh.c | 2 ++
drivers/net/wireless/broadcom/brcm80211/brcmfmac/chip.c | 1 +
drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c | 2 ++
include/linux/mmc/sdio_ids.h | 2 ++
4 files changed, 7 insertions(+)
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcmsdh.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcmsdh.c
@@ -973,8 +973,10 @@ static const struct sdio_device_id brcmf
BRCMF_SDIO_DEVICE(SDIO_DEVICE_ID_BROADCOM_43455),
BRCMF_SDIO_DEVICE(SDIO_DEVICE_ID_BROADCOM_4354),
BRCMF_SDIO_DEVICE(SDIO_DEVICE_ID_BROADCOM_4356),
+ BRCMF_SDIO_DEVICE(SDIO_DEVICE_ID_BROADCOM_4359),
BRCMF_SDIO_DEVICE(SDIO_DEVICE_ID_CYPRESS_4373),
BRCMF_SDIO_DEVICE(SDIO_DEVICE_ID_CYPRESS_43012),
+ BRCMF_SDIO_DEVICE(SDIO_DEVICE_ID_CYPRESS_89359),
{ /* end: all zeroes */ }
};
MODULE_DEVICE_TABLE(sdio, brcmf_sdmmc_ids);
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/chip.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/chip.c
@@ -1408,6 +1408,7 @@ bool brcmf_chip_sr_capable(struct brcmf_
addr = CORE_CC_REG(base, sr_control0);
reg = chip->ops->read32(chip->ctx, addr);
return (reg & CC_SR_CTL0_ENABLE_MASK) != 0;
+ case BRCM_CC_4359_CHIP_ID:
case CY_CC_43012_CHIP_ID:
addr = CORE_CC_REG(pmu->base, retention_ctl);
reg = chip->ops->read32(chip->ctx, addr);
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c
@@ -616,6 +616,7 @@ BRCMF_FW_DEF(43455, "brcmfmac43455-sdio"
BRCMF_FW_DEF(43456, "brcmfmac43456-sdio");
BRCMF_FW_DEF(4354, "brcmfmac4354-sdio");
BRCMF_FW_DEF(4356, "brcmfmac4356-sdio");
+BRCMF_FW_DEF(4359, "brcmfmac4359-sdio");
BRCMF_FW_DEF(4373, "brcmfmac4373-sdio");
BRCMF_FW_DEF(43012, "brcmfmac43012-sdio");
@@ -638,6 +639,7 @@ static const struct brcmf_firmware_mappi
BRCMF_FW_ENTRY(BRCM_CC_4345_CHIP_ID, 0xFFFFFDC0, 43455),
BRCMF_FW_ENTRY(BRCM_CC_4354_CHIP_ID, 0xFFFFFFFF, 4354),
BRCMF_FW_ENTRY(BRCM_CC_4356_CHIP_ID, 0xFFFFFFFF, 4356),
+ BRCMF_FW_ENTRY(BRCM_CC_4359_CHIP_ID, 0xFFFFFFFF, 4359),
BRCMF_FW_ENTRY(CY_CC_4373_CHIP_ID, 0xFFFFFFFF, 4373),
BRCMF_FW_ENTRY(CY_CC_43012_CHIP_ID, 0xFFFFFFFF, 43012)
};
--- a/include/linux/mmc/sdio_ids.h
+++ b/include/linux/mmc/sdio_ids.h
@@ -41,8 +41,10 @@
#define SDIO_DEVICE_ID_BROADCOM_43455 0xa9bf
#define SDIO_DEVICE_ID_BROADCOM_4354 0x4354
#define SDIO_DEVICE_ID_BROADCOM_4356 0x4356
+#define SDIO_DEVICE_ID_BROADCOM_4359 0x4359
#define SDIO_DEVICE_ID_CYPRESS_4373 0x4373
#define SDIO_DEVICE_ID_CYPRESS_43012 43012
+#define SDIO_DEVICE_ID_CYPRESS_89359 0x4355
#define SDIO_VENDOR_ID_INTEL 0x0089
#define SDIO_DEVICE_ID_INTEL_IWMC3200WIMAX 0x1402

View File

@ -1,130 +0,0 @@
From 837482e69a3f0d7cbc73922020012f83635f5ddb Mon Sep 17 00:00:00 2001
From: Wright Feng <wright.feng@cypress.com>
Date: Thu, 12 Dec 2019 00:52:50 +0100
Subject: [PATCH 6/7] brcmfmac: add RSDB condition when setting interface
combinations
With firmware RSDB feature
1. The maximum support interface is four.
2. The maximum difference channel is two.
3. The maximum interfaces of {station/p2p client/AP} are two.
4. The maximum interface of p2p device is one.
Signed-off-by: Wright Feng <wright.feng@cypress.com>
Signed-off-by: Soeren Moch <smoch@web.de>
Reviewed-by: Chi-Hsien Lin <chi-hsien.lin@cypress.com>
Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
---
.../broadcom/brcm80211/brcmfmac/cfg80211.c | 54 ++++++++++++++++---
1 file changed, 46 insertions(+), 8 deletions(-)
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c
@@ -6452,6 +6452,9 @@ brcmf_txrx_stypes[NUM_NL80211_IFTYPES] =
* #STA <= 1, #AP <= 1, channels = 1, 2 total
* #AP <= 4, matching BI, channels = 1, 4 total
*
+ * no p2p and rsdb:
+ * #STA <= 2, #AP <= 2, channels = 2, 4 total
+ *
* p2p, no mchan, and mbss:
*
* #STA <= 1, #P2P-DEV <= 1, #{P2P-CL, P2P-GO} <= 1, channels = 1, 3 total
@@ -6463,6 +6466,10 @@ brcmf_txrx_stypes[NUM_NL80211_IFTYPES] =
* #STA <= 1, #P2P-DEV <= 1, #{P2P-CL, P2P-GO} <= 1, channels = 2, 3 total
* #STA <= 1, #P2P-DEV <= 1, #AP <= 1, #P2P-CL <= 1, channels = 1, 4 total
* #AP <= 4, matching BI, channels = 1, 4 total
+ *
+ * p2p, rsdb, and no mbss:
+ * #STA <= 2, #P2P-DEV <= 1, #{P2P-CL, P2P-GO} <= 2, AP <= 2,
+ * channels = 2, 4 total
*/
static int brcmf_setup_ifmodes(struct wiphy *wiphy, struct brcmf_if *ifp)
{
@@ -6470,13 +6477,14 @@ static int brcmf_setup_ifmodes(struct wi
struct ieee80211_iface_limit *c0_limits = NULL;
struct ieee80211_iface_limit *p2p_limits = NULL;
struct ieee80211_iface_limit *mbss_limits = NULL;
- bool mbss, p2p;
+ bool mbss, p2p, rsdb;
int i, c, n_combos;
mbss = brcmf_feat_is_enabled(ifp, BRCMF_FEAT_MBSS);
p2p = brcmf_feat_is_enabled(ifp, BRCMF_FEAT_P2P);
+ rsdb = brcmf_feat_is_enabled(ifp, BRCMF_FEAT_RSDB);
- n_combos = 1 + !!p2p + !!mbss;
+ n_combos = 1 + !!(p2p && !rsdb) + !!mbss;
combo = kcalloc(n_combos, sizeof(*combo), GFP_KERNEL);
if (!combo)
goto err;
@@ -6487,16 +6495,36 @@ static int brcmf_setup_ifmodes(struct wi
c = 0;
i = 0;
- c0_limits = kcalloc(p2p ? 3 : 2, sizeof(*c0_limits), GFP_KERNEL);
+ if (p2p && rsdb)
+ c0_limits = kcalloc(4, sizeof(*c0_limits), GFP_KERNEL);
+ else if (p2p)
+ c0_limits = kcalloc(3, sizeof(*c0_limits), GFP_KERNEL);
+ else
+ c0_limits = kcalloc(2, sizeof(*c0_limits), GFP_KERNEL);
if (!c0_limits)
goto err;
- c0_limits[i].max = 1;
- c0_limits[i++].types = BIT(NL80211_IFTYPE_STATION);
- if (p2p) {
+ if (p2p && rsdb) {
+ combo[c].num_different_channels = 2;
+ wiphy->interface_modes |= BIT(NL80211_IFTYPE_P2P_CLIENT) |
+ BIT(NL80211_IFTYPE_P2P_GO) |
+ BIT(NL80211_IFTYPE_P2P_DEVICE);
+ c0_limits[i].max = 2;
+ c0_limits[i++].types = BIT(NL80211_IFTYPE_STATION);
+ c0_limits[i].max = 1;
+ c0_limits[i++].types = BIT(NL80211_IFTYPE_P2P_DEVICE);
+ c0_limits[i].max = 2;
+ c0_limits[i++].types = BIT(NL80211_IFTYPE_P2P_CLIENT) |
+ BIT(NL80211_IFTYPE_P2P_GO);
+ c0_limits[i].max = 2;
+ c0_limits[i++].types = BIT(NL80211_IFTYPE_AP);
+ combo[c].max_interfaces = 5;
+ } else if (p2p) {
if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_MCHAN))
combo[c].num_different_channels = 2;
else
combo[c].num_different_channels = 1;
+ c0_limits[i].max = 1;
+ c0_limits[i++].types = BIT(NL80211_IFTYPE_STATION);
wiphy->interface_modes |= BIT(NL80211_IFTYPE_P2P_CLIENT) |
BIT(NL80211_IFTYPE_P2P_GO) |
BIT(NL80211_IFTYPE_P2P_DEVICE);
@@ -6505,16 +6533,26 @@ static int brcmf_setup_ifmodes(struct wi
c0_limits[i].max = 1;
c0_limits[i++].types = BIT(NL80211_IFTYPE_P2P_CLIENT) |
BIT(NL80211_IFTYPE_P2P_GO);
+ combo[c].max_interfaces = i;
+ } else if (rsdb) {
+ combo[c].num_different_channels = 2;
+ c0_limits[i].max = 2;
+ c0_limits[i++].types = BIT(NL80211_IFTYPE_STATION);
+ c0_limits[i].max = 2;
+ c0_limits[i++].types = BIT(NL80211_IFTYPE_AP);
+ combo[c].max_interfaces = 3;
} else {
combo[c].num_different_channels = 1;
c0_limits[i].max = 1;
+ c0_limits[i++].types = BIT(NL80211_IFTYPE_STATION);
+ c0_limits[i].max = 1;
c0_limits[i++].types = BIT(NL80211_IFTYPE_AP);
+ combo[c].max_interfaces = i;
}
- combo[c].max_interfaces = i;
combo[c].n_limits = i;
combo[c].limits = c0_limits;
- if (p2p) {
+ if (p2p && !rsdb) {
c++;
i = 0;
p2p_limits = kcalloc(4, sizeof(*p2p_limits), GFP_KERNEL);

View File

@ -1,38 +0,0 @@
From 2635853ce4ab7654a77ab7080fb56de83408606b Mon Sep 17 00:00:00 2001
From: Wright Feng <wright.feng@cypress.com>
Date: Thu, 12 Dec 2019 00:52:51 +0100
Subject: [PATCH 7/7] brcmfmac: not set mbss in vif if firmware does not
support MBSS
With RSDB mode, FMAC and firmware are able to create 2 or more AP,
so we should not set mbss in vif structure if firmware does not
support MBSS feature.
Signed-off-by: Wright Feng <wright.feng@cypress.com>
Signed-off-by: Soeren Moch <smoch@web.de>
Reviewed-by: Chi-Hsien Lin <chi-hsien.lin@cypress.com>
Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
---
drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c
@@ -5301,6 +5301,7 @@ struct brcmf_cfg80211_vif *brcmf_alloc_v
struct brcmf_cfg80211_vif *vif_walk;
struct brcmf_cfg80211_vif *vif;
bool mbss;
+ struct brcmf_if *ifp = brcmf_get_ifp(cfg->pub, 0);
brcmf_dbg(TRACE, "allocating virtual interface (size=%zu)\n",
sizeof(*vif));
@@ -5313,7 +5314,8 @@ struct brcmf_cfg80211_vif *brcmf_alloc_v
brcmf_init_prof(&vif->profile);
- if (type == NL80211_IFTYPE_AP) {
+ if (type == NL80211_IFTYPE_AP &&
+ brcmf_feat_is_enabled(ifp, BRCMF_FEAT_MBSS)) {
mbss = false;
list_for_each_entry(vif_walk, &cfg->vif_list, list) {
if (vif_walk->wdev.iftype == NL80211_IFTYPE_AP) {

View File

@ -1,66 +0,0 @@
From a32de68edab7b73ded850bcf76cdf6858e92a7e5 Mon Sep 17 00:00:00 2001
From: Dmitry Osipenko <digetx@gmail.com>
Date: Sun, 15 Dec 2019 21:42:24 +0300
Subject: [PATCH] brcmfmac: Keep OOB wake-interrupt disabled when it shouldn't
be enabled
NVIDIA Tegra SoCs do not like when OOB wake is enabled and WiFi interface
is in DOWN state during suspend. This results in a CPU hang on programming
OOB wake-up state of the GPIO controller during of system's suspend.
The solution is trivial: don't enable wake for the OOB interrupt when it
should be disabled.
This fixes hang on Tegra20 (Acer A500) and Tegra30 (Nexus 7) devices which
are using BCM4329 and BCM4330 WiFi chips respectively.
Signed-off-by: Dmitry Osipenko <digetx@gmail.com>
Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
---
.../net/wireless/broadcom/brcm80211/brcmfmac/bcmsdh.c | 10 +++++-----
.../net/wireless/broadcom/brcm80211/brcmfmac/sdio.h | 1 -
2 files changed, 5 insertions(+), 6 deletions(-)
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcmsdh.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcmsdh.c
@@ -120,7 +120,7 @@ int brcmf_sdiod_intr_register(struct brc
brcmf_err("enable_irq_wake failed %d\n", ret);
return ret;
}
- sdiodev->irq_wake = true;
+ disable_irq_wake(pdata->oob_irq_nr);
sdio_claim_host(sdiodev->func1);
@@ -179,10 +179,6 @@ void brcmf_sdiod_intr_unregister(struct
sdio_release_host(sdiodev->func1);
sdiodev->oob_irq_requested = false;
- if (sdiodev->irq_wake) {
- disable_irq_wake(pdata->oob_irq_nr);
- sdiodev->irq_wake = false;
- }
free_irq(pdata->oob_irq_nr, &sdiodev->func1->dev);
sdiodev->irq_en = false;
sdiodev->oob_irq_requested = false;
@@ -1173,6 +1169,10 @@ static int brcmf_ops_sdio_resume(struct
if (ret)
brcmf_err("Failed to probe device on resume\n");
} else {
+ if (sdiodev->wowl_enabled &&
+ sdiodev->settings->bus.sdio.oob_irq_supported)
+ disable_irq_wake(sdiodev->settings->bus.sdio.oob_irq_nr);
+
brcmf_sdiod_freezer_off(sdiodev);
}
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.h
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.h
@@ -178,7 +178,6 @@ struct brcmf_sdio_dev {
bool sd_irq_requested;
bool irq_en; /* irq enable flags */
spinlock_t irq_en_lock;
- bool irq_wake; /* irq wake enable flags */
bool sg_support;
uint max_request_size;
ushort max_segment_count;

View File

@ -1,27 +0,0 @@
From b92c017deda819e45a0f054f6df6b53e645d7fe4 Mon Sep 17 00:00:00 2001
From: zhengbin <zhengbin13@huawei.com>
Date: Tue, 24 Dec 2019 22:16:06 +0800
Subject: [PATCH] brcmfmac: use true,false for bool variable
Fixes coccicheck warning:
drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwsignal.c:911:2-24: WARNING: Assignment of 0/1 to bool variable
Reported-by: Hulk Robot <hulkci@huawei.com>
Signed-off-by: zhengbin <zhengbin13@huawei.com>
Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
---
drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwsignal.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwsignal.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwsignal.c
@@ -908,7 +908,7 @@ static u8 brcmf_fws_hdrpush(struct brcmf
wlh += wlh[1] + 2;
if (entry->send_tim_signal) {
- entry->send_tim_signal = 0;
+ entry->send_tim_signal = false;
wlh[0] = BRCMF_FWS_TYPE_PENDING_TRAFFIC_BMP;
wlh[1] = BRCMF_FWS_TYPE_PENDING_TRAFFIC_BMP_LEN;
wlh[2] = entry->mac_handle;

View File

@ -1,103 +0,0 @@
From 24332f8068ff6df7f16aefee45d514de1de4de80 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= <rafal@milecki.pl>
Date: Thu, 26 Dec 2019 14:30:49 +0100
Subject: [PATCH] brcmfmac: simplify building interface combinations
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Move similar/duplicated code out of combination specific code blocks.
This simplifies code a bit and allows adding more combinations later.
A list of combinations remains unchanged.
Signed-off-by: Rafał Miłecki <rafal@milecki.pl>
Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
---
.../broadcom/brcm80211/brcmfmac/cfg80211.c | 43 ++++++-------------
1 file changed, 14 insertions(+), 29 deletions(-)
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c
@@ -6479,12 +6479,13 @@ static int brcmf_setup_ifmodes(struct wi
struct ieee80211_iface_limit *c0_limits = NULL;
struct ieee80211_iface_limit *p2p_limits = NULL;
struct ieee80211_iface_limit *mbss_limits = NULL;
- bool mbss, p2p, rsdb;
+ bool mbss, p2p, rsdb, mchan;
int i, c, n_combos;
mbss = brcmf_feat_is_enabled(ifp, BRCMF_FEAT_MBSS);
p2p = brcmf_feat_is_enabled(ifp, BRCMF_FEAT_P2P);
rsdb = brcmf_feat_is_enabled(ifp, BRCMF_FEAT_RSDB);
+ mchan = brcmf_feat_is_enabled(ifp, BRCMF_FEAT_MCHAN);
n_combos = 1 + !!(p2p && !rsdb) + !!mbss;
combo = kcalloc(n_combos, sizeof(*combo), GFP_KERNEL);
@@ -6494,6 +6495,10 @@ static int brcmf_setup_ifmodes(struct wi
wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
BIT(NL80211_IFTYPE_ADHOC) |
BIT(NL80211_IFTYPE_AP);
+ if (p2p)
+ wiphy->interface_modes |= BIT(NL80211_IFTYPE_P2P_CLIENT) |
+ BIT(NL80211_IFTYPE_P2P_GO) |
+ BIT(NL80211_IFTYPE_P2P_DEVICE);
c = 0;
i = 0;
@@ -6505,48 +6510,28 @@ static int brcmf_setup_ifmodes(struct wi
c0_limits = kcalloc(2, sizeof(*c0_limits), GFP_KERNEL);
if (!c0_limits)
goto err;
- if (p2p && rsdb) {
- combo[c].num_different_channels = 2;
- wiphy->interface_modes |= BIT(NL80211_IFTYPE_P2P_CLIENT) |
- BIT(NL80211_IFTYPE_P2P_GO) |
- BIT(NL80211_IFTYPE_P2P_DEVICE);
- c0_limits[i].max = 2;
- c0_limits[i++].types = BIT(NL80211_IFTYPE_STATION);
+
+ combo[c].num_different_channels = 1 + (rsdb || (p2p && mchan));
+ c0_limits[i].max = 1 + rsdb;
+ c0_limits[i++].types = BIT(NL80211_IFTYPE_STATION);
+ if (p2p) {
c0_limits[i].max = 1;
c0_limits[i++].types = BIT(NL80211_IFTYPE_P2P_DEVICE);
- c0_limits[i].max = 2;
+ c0_limits[i].max = 1 + rsdb;
c0_limits[i++].types = BIT(NL80211_IFTYPE_P2P_CLIENT) |
BIT(NL80211_IFTYPE_P2P_GO);
+ }
+ if (p2p && rsdb) {
c0_limits[i].max = 2;
c0_limits[i++].types = BIT(NL80211_IFTYPE_AP);
combo[c].max_interfaces = 5;
} else if (p2p) {
- if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_MCHAN))
- combo[c].num_different_channels = 2;
- else
- combo[c].num_different_channels = 1;
- c0_limits[i].max = 1;
- c0_limits[i++].types = BIT(NL80211_IFTYPE_STATION);
- wiphy->interface_modes |= BIT(NL80211_IFTYPE_P2P_CLIENT) |
- BIT(NL80211_IFTYPE_P2P_GO) |
- BIT(NL80211_IFTYPE_P2P_DEVICE);
- c0_limits[i].max = 1;
- c0_limits[i++].types = BIT(NL80211_IFTYPE_P2P_DEVICE);
- c0_limits[i].max = 1;
- c0_limits[i++].types = BIT(NL80211_IFTYPE_P2P_CLIENT) |
- BIT(NL80211_IFTYPE_P2P_GO);
combo[c].max_interfaces = i;
} else if (rsdb) {
- combo[c].num_different_channels = 2;
- c0_limits[i].max = 2;
- c0_limits[i++].types = BIT(NL80211_IFTYPE_STATION);
c0_limits[i].max = 2;
c0_limits[i++].types = BIT(NL80211_IFTYPE_AP);
combo[c].max_interfaces = 3;
} else {
- combo[c].num_different_channels = 1;
- c0_limits[i].max = 1;
- c0_limits[i++].types = BIT(NL80211_IFTYPE_STATION);
c0_limits[i].max = 1;
c0_limits[i++].types = BIT(NL80211_IFTYPE_AP);
combo[c].max_interfaces = i;

View File

@ -1,345 +0,0 @@
From 20f2c5fa3af060401c72e444999470a4cab641cf Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= <rafal@milecki.pl>
Date: Thu, 26 Dec 2019 14:30:50 +0100
Subject: [PATCH] brcmfmac: add initial support for monitor mode
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Report monitor interface availability using cfg80211 and support it in
the add_virtual_intf() and del_virtual_intf() callbacks. This new
feature is conditional and depends on firmware flagging monitor packets.
Receiving monitor frames is already handled by the brcmf_netif_mon_rx().
Signed-off-by: Rafał Miłecki <rafal@milecki.pl>
Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
---
.../broadcom/brcm80211/brcmfmac/cfg80211.c | 112 ++++++++++++++++--
.../broadcom/brcm80211/brcmfmac/core.c | 68 ++++++++++-
.../broadcom/brcm80211/brcmfmac/core.h | 2 +
.../broadcom/brcm80211/brcmfmac/feature.c | 1 +
.../broadcom/brcm80211/brcmfmac/feature.h | 2 +
.../broadcom/brcm80211/brcmfmac/fwil.h | 2 +
6 files changed, 174 insertions(+), 13 deletions(-)
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c
@@ -11,6 +11,7 @@
#include <linux/vmalloc.h>
#include <net/cfg80211.h>
#include <net/netlink.h>
+#include <uapi/linux/if_arp.h>
#include <brcmu_utils.h>
#include <defs.h>
@@ -619,6 +620,82 @@ static bool brcmf_is_ibssmode(struct brc
return vif->wdev.iftype == NL80211_IFTYPE_ADHOC;
}
+/**
+ * brcmf_mon_add_vif() - create monitor mode virtual interface
+ *
+ * @wiphy: wiphy device of new interface.
+ * @name: name of the new interface.
+ */
+static struct wireless_dev *brcmf_mon_add_vif(struct wiphy *wiphy,
+ const char *name)
+{
+ struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
+ struct brcmf_cfg80211_vif *vif;
+ struct net_device *ndev;
+ struct brcmf_if *ifp;
+ int err;
+
+ if (cfg->pub->mon_if) {
+ err = -EEXIST;
+ goto err_out;
+ }
+
+ vif = brcmf_alloc_vif(cfg, NL80211_IFTYPE_MONITOR);
+ if (IS_ERR(vif)) {
+ err = PTR_ERR(vif);
+ goto err_out;
+ }
+
+ ndev = alloc_netdev(sizeof(*ifp), name, NET_NAME_UNKNOWN, ether_setup);
+ if (!ndev) {
+ err = -ENOMEM;
+ goto err_free_vif;
+ }
+ ndev->type = ARPHRD_IEEE80211_RADIOTAP;
+ ndev->ieee80211_ptr = &vif->wdev;
+ ndev->needs_free_netdev = true;
+ ndev->priv_destructor = brcmf_cfg80211_free_netdev;
+ SET_NETDEV_DEV(ndev, wiphy_dev(cfg->wiphy));
+
+ ifp = netdev_priv(ndev);
+ ifp->vif = vif;
+ ifp->ndev = ndev;
+ ifp->drvr = cfg->pub;
+
+ vif->ifp = ifp;
+ vif->wdev.netdev = ndev;
+
+ err = brcmf_net_mon_attach(ifp);
+ if (err) {
+ brcmf_err("Failed to attach %s device\n", ndev->name);
+ free_netdev(ndev);
+ goto err_free_vif;
+ }
+
+ cfg->pub->mon_if = ifp;
+
+ return &vif->wdev;
+
+err_free_vif:
+ brcmf_free_vif(vif);
+err_out:
+ return ERR_PTR(err);
+}
+
+static int brcmf_mon_del_vif(struct wiphy *wiphy, struct wireless_dev *wdev)
+{
+ struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
+ struct net_device *ndev = wdev->netdev;
+
+ ndev->netdev_ops->ndo_stop(ndev);
+
+ brcmf_net_detach(ndev, true);
+
+ cfg->pub->mon_if = NULL;
+
+ return 0;
+}
+
static struct wireless_dev *brcmf_cfg80211_add_iface(struct wiphy *wiphy,
const char *name,
unsigned char name_assign_type,
@@ -641,9 +718,10 @@ static struct wireless_dev *brcmf_cfg802
case NL80211_IFTYPE_STATION:
case NL80211_IFTYPE_AP_VLAN:
case NL80211_IFTYPE_WDS:
- case NL80211_IFTYPE_MONITOR:
case NL80211_IFTYPE_MESH_POINT:
return ERR_PTR(-EOPNOTSUPP);
+ case NL80211_IFTYPE_MONITOR:
+ return brcmf_mon_add_vif(wiphy, name);
case NL80211_IFTYPE_AP:
wdev = brcmf_ap_add_vif(wiphy, name, params);
break;
@@ -826,9 +904,10 @@ int brcmf_cfg80211_del_iface(struct wiph
case NL80211_IFTYPE_STATION:
case NL80211_IFTYPE_AP_VLAN:
case NL80211_IFTYPE_WDS:
- case NL80211_IFTYPE_MONITOR:
case NL80211_IFTYPE_MESH_POINT:
return -EOPNOTSUPP;
+ case NL80211_IFTYPE_MONITOR:
+ return brcmf_mon_del_vif(wiphy, wdev);
case NL80211_IFTYPE_AP:
return brcmf_cfg80211_del_ap_iface(wiphy, wdev);
case NL80211_IFTYPE_P2P_CLIENT:
@@ -6479,9 +6558,10 @@ static int brcmf_setup_ifmodes(struct wi
struct ieee80211_iface_limit *c0_limits = NULL;
struct ieee80211_iface_limit *p2p_limits = NULL;
struct ieee80211_iface_limit *mbss_limits = NULL;
- bool mbss, p2p, rsdb, mchan;
- int i, c, n_combos;
+ bool mon_flag, mbss, p2p, rsdb, mchan;
+ int i, c, n_combos, n_limits;
+ mon_flag = brcmf_feat_is_enabled(ifp, BRCMF_FEAT_MONITOR_FLAG);
mbss = brcmf_feat_is_enabled(ifp, BRCMF_FEAT_MBSS);
p2p = brcmf_feat_is_enabled(ifp, BRCMF_FEAT_P2P);
rsdb = brcmf_feat_is_enabled(ifp, BRCMF_FEAT_RSDB);
@@ -6495,6 +6575,8 @@ static int brcmf_setup_ifmodes(struct wi
wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
BIT(NL80211_IFTYPE_ADHOC) |
BIT(NL80211_IFTYPE_AP);
+ if (mon_flag)
+ wiphy->interface_modes |= BIT(NL80211_IFTYPE_MONITOR);
if (p2p)
wiphy->interface_modes |= BIT(NL80211_IFTYPE_P2P_CLIENT) |
BIT(NL80211_IFTYPE_P2P_GO) |
@@ -6502,18 +6584,18 @@ static int brcmf_setup_ifmodes(struct wi
c = 0;
i = 0;
- if (p2p && rsdb)
- c0_limits = kcalloc(4, sizeof(*c0_limits), GFP_KERNEL);
- else if (p2p)
- c0_limits = kcalloc(3, sizeof(*c0_limits), GFP_KERNEL);
- else
- c0_limits = kcalloc(2, sizeof(*c0_limits), GFP_KERNEL);
+ n_limits = 1 + mon_flag + (p2p ? 2 : 0) + (rsdb || !p2p);
+ c0_limits = kcalloc(n_limits, sizeof(*c0_limits), GFP_KERNEL);
if (!c0_limits)
goto err;
combo[c].num_different_channels = 1 + (rsdb || (p2p && mchan));
c0_limits[i].max = 1 + rsdb;
c0_limits[i++].types = BIT(NL80211_IFTYPE_STATION);
+ if (mon_flag) {
+ c0_limits[i].max = 1;
+ c0_limits[i++].types = BIT(NL80211_IFTYPE_MONITOR);
+ }
if (p2p) {
c0_limits[i].max = 1;
c0_limits[i++].types = BIT(NL80211_IFTYPE_P2P_DEVICE);
@@ -6562,14 +6644,20 @@ static int brcmf_setup_ifmodes(struct wi
if (mbss) {
c++;
i = 0;
- mbss_limits = kcalloc(1, sizeof(*mbss_limits), GFP_KERNEL);
+ n_limits = 1 + mon_flag;
+ mbss_limits = kcalloc(n_limits, sizeof(*mbss_limits),
+ GFP_KERNEL);
if (!mbss_limits)
goto err;
mbss_limits[i].max = 4;
mbss_limits[i++].types = BIT(NL80211_IFTYPE_AP);
+ if (mon_flag) {
+ mbss_limits[i].max = 1;
+ mbss_limits[i++].types = BIT(NL80211_IFTYPE_MONITOR);
+ }
combo[c].beacon_int_infra_match = true;
combo[c].num_different_channels = 1;
- combo[c].max_interfaces = 4;
+ combo[c].max_interfaces = 4 + mon_flag;
combo[c].n_limits = i;
combo[c].limits = mbss_limits;
}
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c
@@ -690,7 +690,7 @@ fail:
return -EBADE;
}
-static void brcmf_net_detach(struct net_device *ndev, bool rtnl_locked)
+void brcmf_net_detach(struct net_device *ndev, bool rtnl_locked)
{
if (ndev->reg_state == NETREG_REGISTERED) {
if (rtnl_locked)
@@ -703,6 +703,72 @@ static void brcmf_net_detach(struct net_
}
}
+static int brcmf_net_mon_open(struct net_device *ndev)
+{
+ struct brcmf_if *ifp = netdev_priv(ndev);
+ struct brcmf_pub *drvr = ifp->drvr;
+ u32 monitor;
+ int err;
+
+ brcmf_dbg(TRACE, "Enter\n");
+
+ err = brcmf_fil_cmd_int_get(ifp, BRCMF_C_GET_MONITOR, &monitor);
+ if (err) {
+ bphy_err(drvr, "BRCMF_C_GET_MONITOR error (%d)\n", err);
+ return err;
+ } else if (monitor) {
+ bphy_err(drvr, "Monitor mode is already enabled\n");
+ return -EEXIST;
+ }
+
+ monitor = 3;
+ err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_MONITOR, monitor);
+ if (err)
+ bphy_err(drvr, "BRCMF_C_SET_MONITOR error (%d)\n", err);
+
+ return err;
+}
+
+static int brcmf_net_mon_stop(struct net_device *ndev)
+{
+ struct brcmf_if *ifp = netdev_priv(ndev);
+ struct brcmf_pub *drvr = ifp->drvr;
+ u32 monitor;
+ int err;
+
+ brcmf_dbg(TRACE, "Enter\n");
+
+ monitor = 0;
+ err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_MONITOR, monitor);
+ if (err)
+ bphy_err(drvr, "BRCMF_C_SET_MONITOR error (%d)\n", err);
+
+ return err;
+}
+
+static const struct net_device_ops brcmf_netdev_ops_mon = {
+ .ndo_open = brcmf_net_mon_open,
+ .ndo_stop = brcmf_net_mon_stop,
+};
+
+int brcmf_net_mon_attach(struct brcmf_if *ifp)
+{
+ struct brcmf_pub *drvr = ifp->drvr;
+ struct net_device *ndev;
+ int err;
+
+ brcmf_dbg(TRACE, "Enter\n");
+
+ ndev = ifp->ndev;
+ ndev->netdev_ops = &brcmf_netdev_ops_mon;
+
+ err = register_netdevice(ndev);
+ if (err)
+ bphy_err(drvr, "Failed to register %s device\n", ndev->name);
+
+ return err;
+}
+
void brcmf_net_setcarrier(struct brcmf_if *ifp, bool on)
{
struct net_device *ndev;
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.h
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.h
@@ -210,6 +210,8 @@ void brcmf_txflowblock_if(struct brcmf_i
void brcmf_txfinalize(struct brcmf_if *ifp, struct sk_buff *txp, bool success);
void brcmf_netif_rx(struct brcmf_if *ifp, struct sk_buff *skb);
void brcmf_netif_mon_rx(struct brcmf_if *ifp, struct sk_buff *skb);
+void brcmf_net_detach(struct net_device *ndev, bool rtnl_locked);
+int brcmf_net_mon_attach(struct brcmf_if *ifp);
void brcmf_net_setcarrier(struct brcmf_if *ifp, bool on);
int __init brcmf_core_init(void);
void __exit brcmf_core_exit(void);
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/feature.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/feature.c
@@ -38,6 +38,7 @@ static const struct brcmf_feat_fwcap brc
{ BRCMF_FEAT_MCHAN, "mchan" },
{ BRCMF_FEAT_P2P, "p2p" },
{ BRCMF_FEAT_MONITOR, "monitor" },
+ { BRCMF_FEAT_MONITOR_FLAG, "rtap" },
{ BRCMF_FEAT_MONITOR_FMT_RADIOTAP, "rtap" },
{ BRCMF_FEAT_DOT11H, "802.11h" }
};
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/feature.h
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/feature.h
@@ -23,6 +23,7 @@
* GSCAN: enhanced scan offload feature.
* FWSUP: Firmware supplicant.
* MONITOR: firmware can pass monitor packets to host.
+ * MONITOR_FLAG: firmware flags monitor packets.
* MONITOR_FMT_RADIOTAP: firmware provides monitor packets with radiotap header
* MONITOR_FMT_HW_RX_HDR: firmware provides monitor packets with hw/ucode header
* DOT11H: firmware supports 802.11h
@@ -43,6 +44,7 @@
BRCMF_FEAT_DEF(GSCAN) \
BRCMF_FEAT_DEF(FWSUP) \
BRCMF_FEAT_DEF(MONITOR) \
+ BRCMF_FEAT_DEF(MONITOR_FLAG) \
BRCMF_FEAT_DEF(MONITOR_FMT_RADIOTAP) \
BRCMF_FEAT_DEF(MONITOR_FMT_HW_RX_HDR) \
BRCMF_FEAT_DEF(DOT11H)
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwil.h
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwil.h
@@ -49,6 +49,8 @@
#define BRCMF_C_GET_PM 85
#define BRCMF_C_SET_PM 86
#define BRCMF_C_GET_REVINFO 98
+#define BRCMF_C_GET_MONITOR 107
+#define BRCMF_C_SET_MONITOR 108
#define BRCMF_C_GET_CURR_RATESET 114
#define BRCMF_C_GET_AP 117
#define BRCMF_C_SET_AP 118

View File

@ -1,24 +0,0 @@
From 627b0d094240c38393b2f2d40626c33a8fff6103 Mon Sep 17 00:00:00 2001
From: yuehaibing <yuehaibing@huawei.com>
Date: Wed, 8 Jan 2020 21:57:48 +0800
Subject: [PATCH] brcmfmac: Remove always false 'idx < 0' statement
idx is declared as u32, it will never less than 0.
Signed-off-by: yuehaibing <yuehaibing@huawei.com>
Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
---
drivers/net/wireless/broadcom/brcm80211/brcmfmac/msgbuf.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/msgbuf.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/msgbuf.c
@@ -365,7 +365,7 @@ brcmf_msgbuf_get_pktid(struct device *de
struct brcmf_msgbuf_pktid *pktid;
struct sk_buff *skb;
- if (idx < 0 || idx >= pktids->array_size) {
+ if (idx >= pktids->array_size) {
brcmf_err("Invalid packet id %d (max %d)\n", idx,
pktids->array_size);
return NULL;

View File

@ -1,100 +0,0 @@
From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= <rafal@milecki.pl>
Date: Fri, 27 Mar 2020 13:40:50 +0100
Subject: [PATCH] brcmfmac: add stub for monitor interface xmit
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
According to the struct net_device_ops documentation .ndo_start_xmit is
"Required; cannot be NULL.". Missing it may crash kernel easily:
[ 341.216709] Unable to handle kernel NULL pointer dereference at virtual address 00000000
[ 341.224836] pgd = 26088755
[ 341.227544] [00000000] *pgd=00000000
[ 341.231135] Internal error: Oops: 80000007 [#1] SMP ARM
[ 341.236367] Modules linked in: pppoe ppp_async iptable_nat brcmfmac xt_state xt_nat xt_conntrack xt_REDIRECT xt_MASQU
[ 341.304689] CPU: 0 PID: 0 Comm: swapper/0 Not tainted 5.4.24 #0
[ 341.310621] Hardware name: BCM5301X
[ 341.314116] PC is at 0x0
[ 341.316664] LR is at dev_hard_start_xmit+0x8c/0x11c
[ 341.321546] pc : [<00000000>] lr : [<c0469fa8>] psr: 60000113
[ 341.327821] sp : c0801c30 ip : c610cf00 fp : c08048e4
[ 341.333051] r10: c073a63a r9 : c08044dc r8 : c6c04e00
[ 341.338283] r7 : 00000000 r6 : c60f5000 r5 : 00000000 r4 : c6a9c3c0
[ 341.344820] r3 : 00000000 r2 : bf25a13c r1 : c60f5000 r0 : c6a9c3c0
[ 341.351358] Flags: nZCv IRQs on FIQs on Mode SVC_32 ISA ARM Segment none
[ 341.358504] Control: 10c5387d Table: 0611c04a DAC: 00000051
[ 341.364257] Process swapper/0 (pid: 0, stack limit = 0xc68ed0ca)
[ 341.370271] Stack: (0xc0801c30 to 0xc0802000)
[ 341.374633] 1c20: c6e7d480 c0802d00 c60f5050 c0801c6c
[ 341.382825] 1c40: c60f5000 c6a9c3c0 c6f90000 c6f9005c c6c04e00 c60f5000 00000000 c6f9005c
[ 341.391015] 1c60: 00000000 c04a033c 00f90200 00000010 c6a9c3c0 c6a9c3c0 c6f90000 00000000
[ 341.399205] 1c80: 00000000 00000000 00000000 c046a7ac c6f9005c 00000001 fffffff4 00000000
[ 341.407395] 1ca0: c6f90200 00000000 c60f5000 c0479550 00000000 c6f90200 c6a9c3c0 16000000
[ 341.415586] 1cc0: 0000001c 6f4ad52f c6197040 b6df9387 36000000 c0520404 c073a80c c6a9c3c0
[ 341.423777] 1ce0: 00000000 c6d643c0 c6a9c3c0 c0800024 00000001 00000001 c6d643c8 c6a9c3c0
[ 341.431967] 1d00: c081b9c0 c7abca80 c610c840 c081b9c0 0000001c 00400000 c6bc5e6c c0522fb4
[ 341.440157] 1d20: c6d64400 00000004 c6bc5e0a 00000000 c60f5000 c7abca80 c081b9c0 c0522f54
[ 341.448348] 1d40: c6a9c3c0 c7abca80 c0803e48 c0549c94 c610c828 0000000a c0801d74 00000003
[ 341.456538] 1d60: c6ec8f0a 00000000 c60f5000 c7abca80 c081b9c0 c0548520 0000000a 00000000
[ 341.464728] 1d80: 00000000 003a0000 00000000 00000000 00000000 00000000 00000000 00000000
[ 341.472919] 1da0: 000002ff 00000000 00000000 16000000 00000000 00000000 00000000 00000000
[ 341.481110] 1dc0: 00000000 0000008f 00000000 00000000 00000000 2d132a69 c6bc5e40 00000000
[ 341.489300] 1de0: c6bc5e40 c6a9c3c0 00000000 c6ec8e50 00000001 c054b070 00000001 00000000
[ 341.497490] 1e00: c0807200 c6bc5e00 00000000 ffffe000 00000100 c054aea4 00000000 00000000
[ 341.505681] 1e20: 00000122 00400000 c0802d00 c0172e80 6f56a70e ffffffff 6f56a70e c7eb9cc0
[ 341.513871] 1e40: c7eb82c0 00000000 c0801e60 c017309c 00000000 00000000 07780000 c07382c0
[ 341.522061] 1e60: 00000000 c7eb9cc0 c0739cc0 c0803f74 c0801e70 c0801e70 c0801ea4 c013d380
[ 341.530253] 1e80: 00000000 000000a0 00000001 c0802084 c0802080 40000001 ffffe000 00000100
[ 341.538443] 1ea0: c0802080 c01021e8 c8803100 10c5387d 00000000 c07341f0 c0739880 0000000a
[ 341.546633] 1ec0: c0734180 00001017 c0802d00 c062aa98 00200002 c062aa60 c8803100 c073984c
[ 341.554823] 1ee0: 00000000 00000001 00000000 c7810000 c8803100 10c5387d 00000000 c011c188
[ 341.563014] 1f00: c073984c c015f0f8 c0804244 c0815ae4 c880210c c8802100 c0801f40 c037c584
[ 341.571204] 1f20: c01035f8 60000013 ffffffff c0801f74 c080afd4 c0800000 10c5387d c0101a8c
[ 341.579395] 1f40: 00000000 004ac9dc c7eba4b4 c010ee60 ffffe000 c0803e68 c0803ea8 00000001
[ 341.587587] 1f60: c080afd4 c062ca20 10c5387d 00000000 00000000 c0801f90 c01035f4 c01035f8
[ 341.595776] 1f80: 60000013 ffffffff 00000051 00000000 ffffe000 c013ff50 000000ce c0803e40
[ 341.603967] 1fa0: c082216c 00000000 00000001 c072ba38 10c5387d c0140214 c0822184 c0700df8
[ 341.612157] 1fc0: ffffffff ffffffff 00000000 c070058c c072ba38 2d162e71 00000000 c0700330
[ 341.620348] 1fe0: 00000051 10c0387d 000000ff 00a521d0 413fc090 00000000 00000000 00000000
[ 341.628558] [<c0469fa8>] (dev_hard_start_xmit) from [<c04a033c>] (sch_direct_xmit+0xe4/0x2bc)
[ 341.637106] [<c04a033c>] (sch_direct_xmit) from [<c046a7ac>] (__dev_queue_xmit+0x6a4/0x72c)
[ 341.645481] [<c046a7ac>] (__dev_queue_xmit) from [<c0520404>] (ip6_finish_output2+0x18c/0x434)
[ 341.654112] [<c0520404>] (ip6_finish_output2) from [<c0522fb4>] (ip6_output+0x5c/0xd0)
[ 341.662053] [<c0522fb4>] (ip6_output) from [<c0549c94>] (mld_sendpack+0x1a0/0x1a8)
[ 341.669640] [<c0549c94>] (mld_sendpack) from [<c054b070>] (mld_ifc_timer_expire+0x1cc/0x2e4)
[ 341.678111] [<c054b070>] (mld_ifc_timer_expire) from [<c0172e80>] (call_timer_fn.constprop.3+0x24/0x98)
[ 341.687527] [<c0172e80>] (call_timer_fn.constprop.3) from [<c017309c>] (run_timer_softirq+0x1a8/0x1e4)
[ 341.696860] [<c017309c>] (run_timer_softirq) from [<c01021e8>] (__do_softirq+0x120/0x2b0)
[ 341.705066] [<c01021e8>] (__do_softirq) from [<c011c188>] (irq_exit+0x78/0x84)
[ 341.712317] [<c011c188>] (irq_exit) from [<c015f0f8>] (__handle_domain_irq+0x60/0xb4)
[ 341.720179] [<c015f0f8>] (__handle_domain_irq) from [<c037c584>] (gic_handle_irq+0x4c/0x90)
[ 341.728549] [<c037c584>] (gic_handle_irq) from [<c0101a8c>] (__irq_svc+0x6c/0x90)
Fixes: 20f2c5fa3af0 ("brcmfmac: add initial support for monitor mode")
Signed-off-by: Rafał Miłecki <rafal@milecki.pl>
---
drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c | 9 +++++++++
1 file changed, 9 insertions(+)
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c
@@ -746,9 +746,18 @@ static int brcmf_net_mon_stop(struct net
return err;
}
+static netdev_tx_t brcmf_net_mon_start_xmit(struct sk_buff *skb,
+ struct net_device *ndev)
+{
+ dev_kfree_skb_any(skb);
+
+ return NETDEV_TX_OK;
+}
+
static const struct net_device_ops brcmf_netdev_ops_mon = {
.ndo_open = brcmf_net_mon_open,
.ndo_stop = brcmf_net_mon_stop,
+ .ndo_start_xmit = brcmf_net_mon_start_xmit,
};
int brcmf_net_mon_attach(struct brcmf_if *ifp)

View File

@ -22,7 +22,7 @@
static int modparam_bad_frames_preempt;
module_param_named(bad_frames_preempt, modparam_bad_frames_preempt, int, 0444);
MODULE_PARM_DESC(bad_frames_preempt,
@@ -2867,10 +2872,10 @@ static int b43_gpio_init(struct b43_wlde
@@ -2869,10 +2874,10 @@ static int b43_gpio_init(struct b43_wlde
u32 mask, set;
b43_maskset32(dev, B43_MMIO_MACCTL, ~B43_MACCTL_GPOUTSMSK, 0);

View File

@ -11,7 +11,7 @@
b43-$(CPTCFG_B43_LEDS) += leds.o
--- a/drivers/net/wireless/broadcom/b43/main.c
+++ b/drivers/net/wireless/broadcom/b43/main.c
@@ -2000,10 +2000,12 @@ static void b43_do_interrupt_thread(stru
@@ -2001,10 +2001,12 @@ static void b43_do_interrupt_thread(stru
dma_reason[0], dma_reason[1],
dma_reason[2], dma_reason[3],
dma_reason[4], dma_reason[5]);

View File

@ -1,6 +1,6 @@
--- a/drivers/net/wireless/broadcom/b43/main.c
+++ b/drivers/net/wireless/broadcom/b43/main.c
@@ -1642,7 +1642,7 @@ static void b43_write_beacon_template(st
@@ -1643,7 +1643,7 @@ static void b43_write_beacon_template(st
len, ram_offset, shm_size_offset, rate);
/* Write the PHY TX control parameters. */
@ -9,7 +9,7 @@
antenna = b43_antenna_to_phyctl(antenna);
ctl = b43_shm_read16(dev, B43_SHM_SHARED, B43_SHM_SH_BEACPHYCTL);
/* We can't send beacons with short preamble. Would get PHY errors. */
@@ -3282,8 +3282,8 @@ static int b43_chip_init(struct b43_wlde
@@ -3284,8 +3284,8 @@ static int b43_chip_init(struct b43_wlde
/* Select the antennae */
if (phy->ops->set_rx_antenna)
@ -20,7 +20,7 @@
if (phy->type == B43_PHYTYPE_B) {
value16 = b43_read16(dev, 0x005E);
@@ -3983,7 +3983,6 @@ static int b43_op_config(struct ieee8021
@@ -3985,7 +3985,6 @@ static int b43_op_config(struct ieee8021
struct b43_wldev *dev = wl->current_dev;
struct b43_phy *phy = &dev->phy;
struct ieee80211_conf *conf = &hw->conf;
@ -28,7 +28,7 @@
int err = 0;
mutex_lock(&wl->mutex);
@@ -4026,11 +4025,9 @@ static int b43_op_config(struct ieee8021
@@ -4028,11 +4027,9 @@ static int b43_op_config(struct ieee8021
}
/* Antennas for RX and management frame TX. */
@ -42,7 +42,7 @@
if (wl->radio_enabled != phy->radio_on) {
if (wl->radio_enabled) {
@@ -5174,6 +5171,47 @@ static int b43_op_get_survey(struct ieee
@@ -5176,6 +5173,47 @@ static int b43_op_get_survey(struct ieee
return 0;
}
@ -90,7 +90,7 @@
static const struct ieee80211_ops b43_hw_ops = {
.tx = b43_op_tx,
.conf_tx = b43_op_conf_tx,
@@ -5195,6 +5233,8 @@ static const struct ieee80211_ops b43_hw
@@ -5197,6 +5235,8 @@ static const struct ieee80211_ops b43_hw
.sw_scan_complete = b43_op_sw_scan_complete_notifier,
.get_survey = b43_op_get_survey,
.rfkill_poll = b43_rfkill_poll,
@ -99,7 +99,7 @@
};
/* Hard-reset the chip. Do not call this directly.
@@ -5496,6 +5536,8 @@ static int b43_one_core_attach(struct b4
@@ -5498,6 +5538,8 @@ static int b43_one_core_attach(struct b4
if (!wldev)
goto out;
@ -108,7 +108,7 @@
wldev->use_pio = b43_modparam_pio;
wldev->dev = dev;
wldev->wl = wl;
@@ -5590,6 +5632,9 @@ static struct b43_wl *b43_wireless_init(
@@ -5592,6 +5634,9 @@ static struct b43_wl *b43_wireless_init(
wiphy_ext_feature_set(hw->wiphy, NL80211_EXT_FEATURE_CQM_RSSI_LIST);

View File

@ -1,6 +1,6 @@
--- a/drivers/net/wireless/broadcom/b43/main.c
+++ b/drivers/net/wireless/broadcom/b43/main.c
@@ -2884,6 +2884,14 @@ static int b43_gpio_init(struct b43_wlde
@@ -2886,6 +2886,14 @@ static int b43_gpio_init(struct b43_wlde
} else if (dev->dev->chip_id == 0x5354) {
/* Don't allow overtaking buttons GPIOs */
set &= 0x2; /* 0x2 is LED GPIO on BCM5354 */

View File

@ -13,7 +13,7 @@ Signed-off-by: Rafał Miłecki <zajec5@gmail.com>
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c
@@ -1554,6 +1554,7 @@ int __init brcmf_core_init(void)
@@ -1557,6 +1557,7 @@ int __init brcmf_core_init(void)
{
if (!schedule_work(&brcmf_driver_work))
return -EBUSY;

View File

@ -10,7 +10,7 @@ Signed-off-by: Rafał Miłecki <zajec5@gmail.com>
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c
@@ -705,8 +705,36 @@ static struct wireless_dev *brcmf_cfg802
@@ -715,8 +715,36 @@ static struct wireless_dev *brcmf_cfg802
struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
struct brcmf_pub *drvr = cfg->pub;
struct wireless_dev *wdev;

View File

@ -14,7 +14,7 @@ Signed-off-by: Phil Elwell <phil@raspberrypi.org>
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c
@@ -2874,6 +2874,10 @@ brcmf_cfg80211_set_power_mgmt(struct wip
@@ -2958,6 +2958,10 @@ brcmf_cfg80211_set_power_mgmt(struct wip
* preference in cfg struct to apply this to
* FW later while initializing the dongle
*/

View File

@ -49,7 +49,7 @@ Signed-off-by: Rafał Miłecki <rafal@milecki.pl>
void brcmf_of_probe(struct device *dev, enum brcmf_bus_type bus_type,
struct brcmf_mp_device *settings)
{
@@ -30,6 +60,8 @@ void brcmf_of_probe(struct device *dev,
@@ -43,6 +73,8 @@ void brcmf_of_probe(struct device *dev,
of_node_put(root);
}

View File

@ -1,6 +1,6 @@
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c
@@ -2826,6 +2826,63 @@ done:
@@ -2910,6 +2910,63 @@ done:
}
static int
@ -64,7 +64,7 @@
brcmf_cfg80211_dump_station(struct wiphy *wiphy, struct net_device *ndev,
int idx, u8 *mac, struct station_info *sinfo)
{
@@ -2915,6 +2972,7 @@ static s32 brcmf_inform_single_bss(struc
@@ -3005,6 +3062,7 @@ static s32 brcmf_inform_single_bss(struc
struct brcmu_chan ch;
u16 channel;
u32 freq;
@ -72,7 +72,7 @@
u16 notify_capability;
u16 notify_interval;
u8 *notify_ie;
@@ -2939,6 +2997,17 @@ static s32 brcmf_inform_single_bss(struc
@@ -3029,6 +3087,17 @@ static s32 brcmf_inform_single_bss(struc
band = NL80211_BAND_5GHZ;
freq = ieee80211_channel_to_frequency(channel, band);
@ -90,7 +90,7 @@
bss_data.chan = ieee80211_get_channel(wiphy, freq);
bss_data.scan_width = NL80211_BSS_CHAN_WIDTH_20;
bss_data.boottime_ns = ktime_to_ns(ktime_get_boottime());
@@ -5356,6 +5425,7 @@ static struct cfg80211_ops brcmf_cfg8021
@@ -5515,6 +5584,7 @@ static struct cfg80211_ops brcmf_cfg8021
.leave_ibss = brcmf_cfg80211_leave_ibss,
.get_station = brcmf_cfg80211_get_station,
.dump_station = brcmf_cfg80211_dump_station,
@ -100,7 +100,7 @@
.add_key = brcmf_cfg80211_add_key,
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c
@@ -1352,6 +1352,8 @@ int brcmf_attach(struct device *dev)
@@ -1356,6 +1356,8 @@ int brcmf_attach(struct device *dev)
/* Link to bus module */
drvr->hdrlen = 0;
@ -109,7 +109,7 @@
/* Attach and link in the protocol */
ret = brcmf_proto_attach(drvr);
@@ -1434,6 +1436,12 @@ void brcmf_detach(struct device *dev)
@@ -1438,6 +1440,12 @@ void brcmf_detach(struct device *dev)
if (drvr == NULL)
return;

View File

@ -1,6 +1,6 @@
--- a/drivers/net/wireless/intel/ipw2x00/ipw2200.c
+++ b/drivers/net/wireless/intel/ipw2x00/ipw2200.c
@@ -11482,6 +11482,15 @@ static const struct attribute_group ipw_
@@ -11470,6 +11470,15 @@ static const struct attribute_group ipw_
.attrs = ipw_sysfs_entries,
};
@ -16,7 +16,7 @@
#ifdef CPTCFG_IPW2200_PROMISCUOUS
static int ipw_prom_open(struct net_device *dev)
{
@@ -11530,15 +11539,6 @@ static netdev_tx_t ipw_prom_hard_start_x
@@ -11518,15 +11527,6 @@ static netdev_tx_t ipw_prom_hard_start_x
return NETDEV_TX_OK;
}

View File

@ -1,6 +1,6 @@
--- a/net/wireless/Kconfig
+++ b/net/wireless/Kconfig
@@ -186,7 +186,7 @@ config CFG80211_WEXT_EXPORT
@@ -188,7 +188,7 @@ config CFG80211_WEXT_EXPORT
endif # CFG80211
config LIB80211
@ -9,7 +9,7 @@
depends on m
default n
help
@@ -196,18 +196,18 @@ config LIB80211
@@ -198,19 +198,19 @@ config LIB80211
Drivers should select this themselves if needed.
config LIB80211_CRYPT_WEP
@ -22,6 +22,7 @@
- tristate
+ tristate "lib80211 CCMP support"
depends on m
depends on CRYPTO
depends on CRYPTO_AES
depends on CRYPTO_CCM

View File

@ -1,6 +1,6 @@
--- a/local-symbols
+++ b/local-symbols
@@ -412,43 +412,6 @@ USB_SIERRA_NET=
@@ -437,43 +437,6 @@ USB_SIERRA_NET=
USB_VL600=
USB_NET_CH9200=
USB_NET_AQC111=
@ -69,7 +69,7 @@
depends on B43 && B43_SSB && SSB_SDIOHOST_POSSIBLE
- select SSB_SDIOHOST
+ depends on SSB_SDIOHOST
---help---
help
Broadcom 43xx device support for Soft-MAC SDIO devices.
@@ -96,13 +96,13 @@ config B43_SDIO
@ -90,7 +90,7 @@
config B43_PHY_G
--- a/drivers/net/wireless/broadcom/b43/main.c
+++ b/drivers/net/wireless/broadcom/b43/main.c
@@ -2851,7 +2851,7 @@ static struct ssb_device *b43_ssb_gpio_d
@@ -2853,7 +2853,7 @@ static struct ssb_device *b43_ssb_gpio_d
{
struct ssb_bus *bus = dev->dev->sdev->bus;
@ -99,7 +99,7 @@
return (bus->chipco.dev ? bus->chipco.dev : bus->pcicore.dev);
#else
return bus->chipco.dev;
@@ -4868,7 +4868,7 @@ static int b43_wireless_core_init(struct
@@ -4870,7 +4870,7 @@ static int b43_wireless_core_init(struct
}
if (sprom->boardflags_lo & B43_BFL_XTAL_NOSLOW)
hf |= B43_HF_DSCRQ; /* Disable slowclock requests from ucode. */
@ -117,7 +117,7 @@
- select SSB
+ depends on SSB
depends on FW_LOADER
---help---
help
b43legacy is a driver for 802.11b devices from Broadcom (BCM4301 and
@@ -25,15 +25,15 @@ config B43LEGACY
config B43LEGACY_PCI_AUTOSELECT
@ -140,7 +140,7 @@
# LED support
--- a/drivers/net/wireless/broadcom/b43legacy/main.c
+++ b/drivers/net/wireless/broadcom/b43legacy/main.c
@@ -1906,7 +1906,7 @@ static int b43legacy_gpio_init(struct b4
@@ -1907,7 +1907,7 @@ static int b43legacy_gpio_init(struct b4
if (dev->dev->id.revision >= 2)
mask |= 0x0010; /* FIXME: This is redundant. */
@ -149,7 +149,7 @@
pcidev = bus->pcicore.dev;
#endif
gpiodev = bus->chipco.dev ? : pcidev;
@@ -1925,7 +1925,7 @@ static void b43legacy_gpio_cleanup(struc
@@ -1926,7 +1926,7 @@ static void b43legacy_gpio_cleanup(struc
struct ssb_bus *bus = dev->dev->bus;
struct ssb_device *gpiodev, *pcidev = NULL;
@ -160,8 +160,8 @@
gpiodev = bus->chipco.dev ? : pcidev;
--- a/drivers/net/wireless/broadcom/brcm80211/brcmsmac/led.h
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmsmac/led.h
@@ -22,7 +22,7 @@ struct brcms_led {
bool active_low;
@@ -24,7 +24,7 @@ struct brcms_led {
struct gpio_desc *gpiod;
};
-#ifdef CPTCFG_BCMA_DRIVER_GPIO
@ -192,7 +192,7 @@
select BRCMUTIL
--- a/Kconfig.local
+++ b/Kconfig.local
@@ -1240,117 +1240,6 @@ config BACKPORTED_USB_NET_CH9200
@@ -1315,117 +1315,6 @@ config BACKPORTED_USB_NET_CH9200
config BACKPORTED_USB_NET_AQC111
tristate
default USB_NET_AQC111

View File

@ -0,0 +1,51 @@
From patchwork Thu Dec 27 14:05:26 2018
Content-Type: text/plain; charset="utf-8"
MIME-Version: 1.0
Content-Transfer-Encoding: 8bit
X-Patchwork-Submitter: Tom Psyborg <pozega.tomislav@gmail.com>
X-Patchwork-Id: 10743707
X-Patchwork-Delegate: kvalo@adurom.com
From: =?utf-8?q?Tomislav_Po=C5=BEega?= <pozega.tomislav@gmail.com>
To: linux-wireless@vger.kernel.org
Cc: kvalo@codeaurora.org, hauke@hauke-m.de, nbd@nbd.name,
john@phrozen.org, sgruszka@redhat.com, daniel@makrotopia.org
Subject: [PATCH 2/2] rt2x00: define RF5592 in init_eeprom routine
Date: Thu, 27 Dec 2018 15:05:26 +0100
Message-Id: <1545919526-4074-2-git-send-email-pozega.tomislav@gmail.com>
X-Mailer: git-send-email 1.7.0.4
In-Reply-To: <1545919526-4074-1-git-send-email-pozega.tomislav@gmail.com>
References: <1545919526-4074-1-git-send-email-pozega.tomislav@gmail.com>
MIME-Version: 1.0
Sender: linux-wireless-owner@vger.kernel.org
Precedence: bulk
List-ID: <linux-wireless.vger.kernel.org>
X-Mailing-List: linux-wireless@vger.kernel.org
X-Virus-Scanned: ClamAV using ClamSMTP
This patch fixes following crash on Linksys EA2750 during 5GHz wifi
init:
[ 7.955153] rt2800pci 0000:01:00.0: card - bus=0x1, slot = 0x0 irq=4
[ 7.962259] rt2800pci 0000:01:00.0: loaded eeprom from mtd device "Factory"
[ 7.969435] ieee80211 phy0: rt2x00_set_rt: Info - RT chipset 5592, rev 0222 detected
[ 7.977348] ieee80211 phy0: rt2800_init_eeprom: Error - Invalid RF chipset 0x0000 detected
[ 7.985793] ieee80211 phy0: rt2x00lib_probe_dev: Error - Failed to allocate device
[ 7.993569] CPU 0 Unable to handle kernel paging request at virtual address 00000024, epc == 800c8f54, ra == 80249ff8
[ 8.004408] Oops[#1]:
Signed-off-by: Tomislav Požega <pozega.tomislav@gmail.com>
---
drivers/net/wireless/ralink/rt2x00/rt2800lib.c | 2 ++
1 files changed, 2 insertions(+), 0 deletions(-)
--- a/drivers/net/wireless/ralink/rt2x00/rt2800lib.c
+++ b/drivers/net/wireless/ralink/rt2x00/rt2800lib.c
@@ -9416,6 +9416,8 @@ static int rt2800_init_eeprom(struct rt2
rf = RF3853;
else if (rt2x00_rt(rt2x00dev, RT5350))
rf = RF5350;
+ else if (rt2x00_rt(rt2x00dev, RT5592))
+ rf = RF5592;
else
rf = rt2x00_get_field16(eeprom, EEPROM_NIC_CONF0_RF_TYPE);

View File

@ -1,6 +1,6 @@
--- a/local-symbols
+++ b/local-symbols
@@ -313,6 +313,7 @@ RT2X00_LIB_FIRMWARE=
@@ -332,6 +332,7 @@ RT2X00_LIB_FIRMWARE=
RT2X00_LIB_CRYPTO=
RT2X00_LIB_LEDS=
RT2X00_LIB_DEBUGFS=
@ -25,7 +25,7 @@
+ select RT2X00_LIB_EEPROM
select RT2800_LIB
select RT2800_LIB_MMIO
---help---
help
@@ -266,6 +268,9 @@ config RT2X00_LIB_FIRMWARE
config RT2X00_LIB_CRYPTO
bool
@ -95,7 +95,7 @@
/* Firmware functions */
static char *rt2800soc_get_firmware_name(struct rt2x00_dev *rt2x00dev)
{
@@ -166,7 +153,6 @@ static const struct rt2800_ops rt2800soc
@@ -167,7 +154,6 @@ static const struct rt2800_ops rt2800soc
.register_multiread = rt2x00mmio_register_multiread,
.register_multiwrite = rt2x00mmio_register_multiwrite,
.regbusy_read = rt2x00mmio_regbusy_read,
@ -127,7 +127,7 @@
DECLARE_KFIFO_PTR(txstatus_fifo, u32);
--- a/drivers/net/wireless/ralink/rt2x00/rt2x00dev.c
+++ b/drivers/net/wireless/ralink/rt2x00/rt2x00dev.c
@@ -1418,6 +1418,10 @@ int rt2x00lib_probe_dev(struct rt2x00_de
@@ -1406,6 +1406,10 @@ int rt2x00lib_probe_dev(struct rt2x00_de
INIT_DELAYED_WORK(&rt2x00dev->autowakeup_work, rt2x00lib_autowakeup);
INIT_WORK(&rt2x00dev->sleep_work, rt2x00lib_sleep);
@ -138,7 +138,7 @@
/*
* Let the driver probe the device to detect the capabilities.
*/
@@ -1561,6 +1565,11 @@ void rt2x00lib_remove_dev(struct rt2x00_
@@ -1549,6 +1553,11 @@ void rt2x00lib_remove_dev(struct rt2x00_
* Free the driver data.
*/
kfree(rt2x00dev->drv_data);

View File

@ -17,7 +17,7 @@ Signed-off-by: John Crispin <blogic@openwrt.org>
select RT2800_LIB
select RT2800_LIB_MMIO
+ select MTD if SOC_RT288X || SOC_RT305X
---help---
help
This adds support for Ralink WiSoC devices.
Supported chips: RT2880, RT3050, RT3052, RT3350, RT3352.
--- a/drivers/net/wireless/ralink/rt2x00/rt2x00eeprom.c

View File

@ -13,7 +13,7 @@ Signed-off-by: John Crispin <blogic@openwrt.org>
--- a/drivers/net/wireless/ralink/rt2x00/rt2800soc.c
+++ b/drivers/net/wireless/ralink/rt2x00/rt2800soc.c
@@ -223,10 +223,17 @@ static int rt2800soc_probe(struct platfo
@@ -224,10 +224,17 @@ static int rt2800soc_probe(struct platfo
return rt2x00soc_probe(pdev, &rt2800soc_ops);
}

View File

@ -8,7 +8,7 @@
#include "rt2x00.h"
#include "rt2800lib.h"
@@ -9531,6 +9532,17 @@ static int rt2800_init_eeprom(struct rt2
@@ -9530,6 +9531,17 @@ static int rt2800_init_eeprom(struct rt2
rt2800_init_led(rt2x00dev, &rt2x00dev->led_assoc, LED_TYPE_ASSOC);
rt2800_init_led(rt2x00dev, &rt2x00dev->led_qual, LED_TYPE_QUALITY);

View File

@ -1,6 +1,6 @@
--- a/drivers/net/wireless/ralink/rt2x00/rt2x00dev.c
+++ b/drivers/net/wireless/ralink/rt2x00/rt2x00dev.c
@@ -1356,7 +1356,7 @@ static inline void rt2x00lib_set_if_comb
@@ -1344,7 +1344,7 @@ static inline void rt2x00lib_set_if_comb
*/
if_limit = &rt2x00dev->if_limits_ap;
if_limit->max = rt2x00dev->ops->max_ap_intf;

View File

@ -31,7 +31,7 @@ Tested-by: Christoph Krapp <achterin@googlemail.com>
static int rt2x00lib_probe_hw(struct rt2x00_dev *rt2x00dev)
{
struct hw_mode_spec *spec = &rt2x00dev->spec;
@@ -1211,6 +1224,10 @@ static int rt2x00lib_probe_hw(struct rt2
@@ -1210,6 +1223,10 @@ static int rt2x00lib_probe_hw(struct rt2
#undef RT2X00_TASKLET_INIT

View File

@ -30,7 +30,7 @@ Signed-off-by: Tomislav Po=C5=BEega <pozega.tomislav@gmail.com>
* EEPROM LNA
--- a/drivers/net/wireless/ralink/rt2x00/rt2800lib.c
+++ b/drivers/net/wireless/ralink/rt2x00/rt2800lib.c
@@ -4359,6 +4359,45 @@ static void rt2800_config_channel(struct
@@ -4356,6 +4356,45 @@ static void rt2800_config_channel(struct
rt2800_iq_calibrate(rt2x00dev, rf->channel);
}
@ -76,7 +76,7 @@ Signed-off-by: Tomislav Po=C5=BEega <pozega.tomislav@gmail.com>
bbp = rt2800_bbp_read(rt2x00dev, 4);
rt2x00_set_field8(&bbp, BBP4_BANDWIDTH, 2 * conf_is_ht40(conf));
rt2800_bbp_write(rt2x00dev, 4, bbp);
@@ -9560,7 +9599,8 @@ static int rt2800_init_eeprom(struct rt2
@@ -9559,7 +9598,8 @@ static int rt2800_init_eeprom(struct rt2
*/
eeprom = rt2800_eeprom_read(rt2x00dev, EEPROM_NIC_CONF1);
@ -86,7 +86,7 @@ Signed-off-by: Tomislav Po=C5=BEega <pozega.tomislav@gmail.com>
if (rt2x00_get_field16(eeprom,
EEPROM_NIC_CONF1_EXTERNAL_TX0_PA_3352))
__set_bit(CAPABILITY_EXTERNAL_PA_TX0,
@@ -9571,6 +9611,18 @@ static int rt2800_init_eeprom(struct rt2
@@ -9570,6 +9610,18 @@ static int rt2800_init_eeprom(struct rt2
&rt2x00dev->cap_flags);
}

View File

@ -1,6 +1,6 @@
--- a/drivers/net/wireless/ralink/rt2x00/rt2800lib.c
+++ b/drivers/net/wireless/ralink/rt2x00/rt2800lib.c
@@ -8422,6 +8422,56 @@ static void rt2800_init_rfcsr_5592(struc
@@ -8419,6 +8419,56 @@ static void rt2800_init_rfcsr_5592(struc
rt2800_led_open_drain_enable(rt2x00dev);
}
@ -57,7 +57,7 @@
static void rt2800_bbp_core_soft_reset(struct rt2x00_dev *rt2x00dev,
bool set_bw, bool is_ht40)
{
@@ -9029,6 +9079,7 @@ static void rt2800_init_rfcsr_6352(struc
@@ -9026,6 +9076,7 @@ static void rt2800_init_rfcsr_6352(struc
rt2800_rfcsr_write_dccal(rt2x00dev, 5, 0x00);
rt2800_rfcsr_write_dccal(rt2x00dev, 17, 0x7C);

View File

@ -1,6 +1,6 @@
--- a/drivers/net/wireless/ralink/rt2x00/rt2800lib.c
+++ b/drivers/net/wireless/ralink/rt2x00/rt2800lib.c
@@ -8472,6 +8472,155 @@ static void rt2800_rf_self_txdc_cal(stru
@@ -8469,6 +8469,155 @@ static void rt2800_rf_self_txdc_cal(stru
rt2x00_info(rt2x00dev, "RF Tx self calibration end\n");
}
@ -156,7 +156,7 @@
static void rt2800_bbp_core_soft_reset(struct rt2x00_dev *rt2x00dev,
bool set_bw, bool is_ht40)
{
@@ -9079,6 +9228,7 @@ static void rt2800_init_rfcsr_6352(struc
@@ -9076,6 +9225,7 @@ static void rt2800_init_rfcsr_6352(struc
rt2800_rfcsr_write_dccal(rt2x00dev, 5, 0x00);
rt2800_rfcsr_write_dccal(rt2x00dev, 17, 0x7C);

View File

@ -1,6 +1,6 @@
--- a/drivers/net/wireless/ralink/rt2x00/rt2800lib.c
+++ b/drivers/net/wireless/ralink/rt2x00/rt2800lib.c
@@ -8621,6 +8621,70 @@ static void rt2800_r_calibration(struct
@@ -8618,6 +8618,70 @@ static void rt2800_r_calibration(struct
rt2800_register_write(rt2x00dev, PWR_PIN_CFG, MAC_PWR_PIN_CFG);
}
@ -71,7 +71,7 @@
static void rt2800_bbp_core_soft_reset(struct rt2x00_dev *rt2x00dev,
bool set_bw, bool is_ht40)
{
@@ -9230,6 +9294,7 @@ static void rt2800_init_rfcsr_6352(struc
@@ -9227,6 +9291,7 @@ static void rt2800_init_rfcsr_6352(struc
rt2800_r_calibration(rt2x00dev);
rt2800_rf_self_txdc_cal(rt2x00dev);

View File

@ -1,6 +1,6 @@
--- a/drivers/net/wireless/ralink/rt2x00/rt2800lib.c
+++ b/drivers/net/wireless/ralink/rt2x00/rt2800lib.c
@@ -8685,6 +8685,384 @@ static void rt2800_rxdcoc_calibration(st
@@ -8682,6 +8682,384 @@ static void rt2800_rxdcoc_calibration(st
rt2800_rfcsr_write_bank(rt2x00dev, 0, 2, saverfb0r2);
}
@ -385,7 +385,7 @@
static void rt2800_bbp_core_soft_reset(struct rt2x00_dev *rt2x00dev,
bool set_bw, bool is_ht40)
{
@@ -9297,6 +9675,7 @@ static void rt2800_init_rfcsr_6352(struc
@@ -9294,6 +9672,7 @@ static void rt2800_init_rfcsr_6352(struc
rt2800_rxdcoc_calibration(rt2x00dev);
rt2800_bw_filter_calibration(rt2x00dev, true);
rt2800_bw_filter_calibration(rt2x00dev, false);

View File

@ -1,6 +1,6 @@
--- a/drivers/net/wireless/ralink/rt2x00/rt2800lib.c
+++ b/drivers/net/wireless/ralink/rt2x00/rt2800lib.c
@@ -9063,6 +9063,943 @@ restore_value:
@@ -9060,6 +9060,943 @@ restore_value:
rt2800_register_write(rt2x00dev, MAC_SYS_CTRL, savemacsysctrl);
}
@ -944,7 +944,7 @@
static void rt2800_bbp_core_soft_reset(struct rt2x00_dev *rt2x00dev,
bool set_bw, bool is_ht40)
{
@@ -9675,6 +10612,7 @@ static void rt2800_init_rfcsr_6352(struc
@@ -9672,6 +10609,7 @@ static void rt2800_init_rfcsr_6352(struc
rt2800_rxdcoc_calibration(rt2x00dev);
rt2800_bw_filter_calibration(rt2x00dev, true);
rt2800_bw_filter_calibration(rt2x00dev, false);

View File

@ -0,0 +1,139 @@
--- a/drivers/net/wireless/ralink/rt2x00/rt2800lib.h
+++ b/drivers/net/wireless/ralink/rt2x00/rt2800lib.h
@@ -78,6 +78,9 @@ struct rt2800_ops {
int (*drv_init_registers)(struct rt2x00_dev *rt2x00dev);
__le32 *(*drv_get_txwi)(struct queue_entry *entry);
unsigned int (*drv_get_dma_done)(struct data_queue *queue);
+ int (*hw_get_chippkg)(void);
+ int (*hw_get_chipver)(void);
+ int (*hw_get_chipeco)(void);
};
static inline u32 rt2800_register_read(struct rt2x00_dev *rt2x00dev,
@@ -195,6 +198,27 @@ static inline unsigned int rt2800_drv_ge
return rt2800ops->drv_get_dma_done(queue);
}
+static inline int rt2800_hw_get_chippkg(struct rt2x00_dev *rt2x00dev)
+{
+ const struct rt2800_ops *rt2800ops = rt2x00dev->ops->drv;
+
+ return rt2800ops->hw_get_chippkg();
+}
+
+static inline int rt2800_hw_get_chipver(struct rt2x00_dev *rt2x00dev)
+{
+ const struct rt2800_ops *rt2800ops = rt2x00dev->ops->drv;
+
+ return rt2800ops->hw_get_chipver();
+}
+
+static inline int rt2800_hw_get_chipeco(struct rt2x00_dev *rt2x00dev)
+{
+ const struct rt2800_ops *rt2800ops = rt2x00dev->ops->drv;
+
+ return rt2800ops->hw_get_chipeco();
+}
+
void rt2800_mcu_request(struct rt2x00_dev *rt2x00dev,
const u8 command, const u8 token,
const u8 arg0, const u8 arg1);
--- a/drivers/net/wireless/ralink/rt2x00/rt2800pci.c
+++ b/drivers/net/wireless/ralink/rt2x00/rt2800pci.c
@@ -286,6 +286,10 @@ static int rt2800pci_read_eeprom(struct
return retval;
}
+static int rt2800pci_get_chippkg(void) { return 0; }
+static int rt2800pci_get_chipver(void) { return 0; }
+static int rt2800pci_get_chipeco(void) { return 0; }
+
static const struct ieee80211_ops rt2800pci_mac80211_ops = {
.tx = rt2x00mac_tx,
.start = rt2x00mac_start,
@@ -328,6 +332,9 @@ static const struct rt2800_ops rt2800pci
.drv_init_registers = rt2800mmio_init_registers,
.drv_get_txwi = rt2800mmio_get_txwi,
.drv_get_dma_done = rt2800mmio_get_dma_done,
+ .hw_get_chippkg = rt2800pci_get_chippkg,
+ .hw_get_chipver = rt2800pci_get_chipver,
+ .hw_get_chipeco = rt2800pci_get_chipeco,
};
static const struct rt2x00lib_ops rt2800pci_rt2x00_ops = {
--- a/drivers/net/wireless/ralink/rt2x00/rt2800soc.c
+++ b/drivers/net/wireless/ralink/rt2x00/rt2800soc.c
@@ -27,6 +27,12 @@
#include "rt2800lib.h"
#include "rt2800mmio.h"
+/* Needed to probe CHIP_VER register on MT7620 */
+#ifdef CONFIG_SOC_MT7620
+#include <asm/mach-ralink/ralink_regs.h>
+#include <asm/mach-ralink/mt7620.h>
+#endif
+
/* Allow hardware encryption to be disabled. */
static bool modparam_nohwcrypt;
module_param_named(nohwcrypt, modparam_nohwcrypt, bool, 0444);
@@ -118,6 +124,27 @@ static int rt2800soc_write_firmware(stru
return 0;
}
+#ifdef CONFIG_SOC_MT7620
+static int rt2800soc_get_chippkg(void)
+{
+ return mt7620_get_pkg();
+}
+
+static int rt2800soc_get_chipver(void)
+{
+ return mt7620_get_chipver();
+}
+
+static int rt2800soc_get_chipeco(void)
+{
+ return mt7620_get_eco();
+}
+#else
+static int rt2800soc_get_chippkg(void) { return 0; }
+static int rt2800soc_get_chipver(void) { return 0; }
+static int rt2800soc_get_chipeco(void) { return 0; }
+#endif
+
static const struct ieee80211_ops rt2800soc_mac80211_ops = {
.tx = rt2x00mac_tx,
.start = rt2x00mac_start,
@@ -159,6 +186,9 @@ static const struct rt2800_ops rt2800soc
.drv_init_registers = rt2800mmio_init_registers,
.drv_get_txwi = rt2800mmio_get_txwi,
.drv_get_dma_done = rt2800mmio_get_dma_done,
+ .hw_get_chippkg = rt2800soc_get_chippkg,
+ .hw_get_chipver = rt2800soc_get_chipver,
+ .hw_get_chipeco = rt2800soc_get_chipeco,
};
static const struct rt2x00lib_ops rt2800soc_rt2x00_ops = {
--- a/drivers/net/wireless/ralink/rt2x00/rt2800usb.c
+++ b/drivers/net/wireless/ralink/rt2x00/rt2800usb.c
@@ -628,6 +628,10 @@ static int rt2800usb_probe_hw(struct rt2
return 0;
}
+static int rt2800usb_get_chippkg(void) { return 0; }
+static int rt2800usb_get_chipver(void) { return 0; }
+static int rt2800usb_get_chipeco(void) { return 0; }
+
static const struct ieee80211_ops rt2800usb_mac80211_ops = {
.tx = rt2x00mac_tx,
.start = rt2x00mac_start,
@@ -671,6 +675,9 @@ static const struct rt2800_ops rt2800usb
.drv_init_registers = rt2800usb_init_registers,
.drv_get_txwi = rt2800usb_get_txwi,
.drv_get_dma_done = rt2800usb_get_dma_done,
+ .hw_get_chippkg = rt2800usb_get_chippkg,
+ .hw_get_chipver = rt2800usb_get_chipver,
+ .hw_get_chipeco = rt2800usb_get_chipeco,
};
static const struct rt2x00lib_ops rt2800usb_rt2x00_ops = {

View File

@ -0,0 +1,408 @@
--- a/drivers/net/wireless/ralink/rt2x00/rt2800.h
+++ b/drivers/net/wireless/ralink/rt2x00/rt2800.h
@@ -1042,6 +1042,11 @@
#define MIMO_PS_CFG_RX_STBY_POL FIELD32(0x00000010)
#define MIMO_PS_CFG_RX_RX_STBY0 FIELD32(0x00000020)
+#define BB_PA_MODE_CFG0 0x1214
+#define BB_PA_MODE_CFG1 0x1218
+#define RF_PA_MODE_CFG0 0x121C
+#define RF_PA_MODE_CFG1 0x1220
+
/*
* EDCA_AC0_CFG:
*/
--- a/drivers/net/wireless/ralink/rt2x00/rt2800lib.c
+++ b/drivers/net/wireless/ralink/rt2x00/rt2800lib.c
@@ -3685,14 +3685,16 @@ static void rt2800_config_channel_rf7620
rt2x00_set_field8(&rfcsr, RFCSR19_K, rf->rf4);
rt2800_rfcsr_write(rt2x00dev, 19, rfcsr);
- /* Default: XO=20MHz , SDM mode */
- rfcsr = rt2800_rfcsr_read(rt2x00dev, 16);
- rt2x00_set_field8(&rfcsr, RFCSR16_SDM_MODE_MT7620, 0x80);
- rt2800_rfcsr_write(rt2x00dev, 16, rfcsr);
-
- rfcsr = rt2800_rfcsr_read(rt2x00dev, 21);
- rt2x00_set_field8(&rfcsr, RFCSR21_BIT8, 1);
- rt2800_rfcsr_write(rt2x00dev, 21, rfcsr);
+ if (rt2800_hw_get_chipver(rt2x00dev) > 1) {
+ /* Default: XO=20MHz , SDM mode */
+ rfcsr = rt2800_rfcsr_read(rt2x00dev, 16);
+ rt2x00_set_field8(&rfcsr, RFCSR16_SDM_MODE_MT7620, 0x80);
+ rt2800_rfcsr_write(rt2x00dev, 16, rfcsr);
+
+ rfcsr = rt2800_rfcsr_read(rt2x00dev, 21);
+ rt2x00_set_field8(&rfcsr, RFCSR21_BIT8, 1);
+ rt2800_rfcsr_write(rt2x00dev, 21, rfcsr);
+ }
rfcsr = rt2800_rfcsr_read(rt2x00dev, 1);
rt2x00_set_field8(&rfcsr, RFCSR1_TX2_EN_MT7620,
@@ -3726,18 +3728,23 @@ static void rt2800_config_channel_rf7620
rt2800_rfcsr_write_dccal(rt2x00dev, 59, 0x20);
}
- if (conf_is_ht40(conf)) {
- rt2800_rfcsr_write_dccal(rt2x00dev, 58, 0x08);
- rt2800_rfcsr_write_dccal(rt2x00dev, 59, 0x08);
- } else {
- rt2800_rfcsr_write_dccal(rt2x00dev, 58, 0x28);
- rt2800_rfcsr_write_dccal(rt2x00dev, 59, 0x28);
+ if (rt2800_hw_get_chipver(rt2x00dev) > 1) {
+ if (conf_is_ht40(conf)) {
+ rt2800_rfcsr_write_dccal(rt2x00dev, 58, 0x08);
+ rt2800_rfcsr_write_dccal(rt2x00dev, 59, 0x08);
+ } else {
+ rt2800_rfcsr_write_dccal(rt2x00dev, 58, 0x28);
+ rt2800_rfcsr_write_dccal(rt2x00dev, 59, 0x28);
+ }
}
- rfcsr = rt2800_rfcsr_read(rt2x00dev, 28);
- rt2x00_set_field8(&rfcsr, RFCSR28_CH11_HT40,
- conf_is_ht40(conf) && (rf->channel == 11));
- rt2800_rfcsr_write(rt2x00dev, 28, rfcsr);
+ if (rt2800_hw_get_chipver(rt2x00dev) > 1 &&
+ rt2800_hw_get_chipeco(rt2x00dev) == 2) {
+ rfcsr = rt2800_rfcsr_read(rt2x00dev, 28);
+ rt2x00_set_field8(&rfcsr, RFCSR28_CH11_HT40,
+ conf_is_ht40(conf) && (rf->channel == 11));
+ rt2800_rfcsr_write(rt2x00dev, 28, rfcsr);
+ }
if (!test_bit(DEVICE_STATE_SCANNING, &rt2x00dev->flags)) {
if (conf_is_ht40(conf)) {
@@ -3837,25 +3844,29 @@ static void rt2800_config_alc(struct rt2
if (i == 10000)
rt2x00_warn(rt2x00dev, "Wait MAC Status to MAX !!!\n");
- if (chan->center_freq > 2457) {
- bbp = rt2800_bbp_read(rt2x00dev, 30);
- bbp = 0x40;
- rt2800_bbp_write(rt2x00dev, 30, bbp);
- rt2800_rfcsr_write(rt2x00dev, 39, 0);
- if (rt2x00_has_cap_external_lna_bg(rt2x00dev))
- rt2800_rfcsr_write(rt2x00dev, 42, 0xfb);
- else
- rt2800_rfcsr_write(rt2x00dev, 42, 0x7b);
- } else {
- bbp = rt2800_bbp_read(rt2x00dev, 30);
- bbp = 0x1f;
- rt2800_bbp_write(rt2x00dev, 30, bbp);
- rt2800_rfcsr_write(rt2x00dev, 39, 0x80);
- if (rt2x00_has_cap_external_lna_bg(rt2x00dev))
- rt2800_rfcsr_write(rt2x00dev, 42, 0xdb);
- else
- rt2800_rfcsr_write(rt2x00dev, 42, 0x5b);
+ if (rt2800_hw_get_chipver(rt2x00dev) > 1 &&
+ rt2800_hw_get_chipeco(rt2x00dev) >= 2) {
+ if (chan->center_freq > 2457) {
+ bbp = rt2800_bbp_read(rt2x00dev, 30);
+ bbp = 0x40;
+ rt2800_bbp_write(rt2x00dev, 30, bbp);
+ rt2800_rfcsr_write(rt2x00dev, 39, 0);
+ if (rt2x00_has_cap_external_lna_bg(rt2x00dev))
+ rt2800_rfcsr_write(rt2x00dev, 42, 0xfb);
+ else
+ rt2800_rfcsr_write(rt2x00dev, 42, 0x7b);
+ } else {
+ bbp = rt2800_bbp_read(rt2x00dev, 30);
+ bbp = 0x1f;
+ rt2800_bbp_write(rt2x00dev, 30, bbp);
+ rt2800_rfcsr_write(rt2x00dev, 39, 0x80);
+ if (rt2x00_has_cap_external_lna_bg(rt2x00dev))
+ rt2800_rfcsr_write(rt2x00dev, 42, 0xdb);
+ else
+ rt2800_rfcsr_write(rt2x00dev, 42, 0x5b);
+ }
}
+
rt2800_register_write(rt2x00dev, MAC_SYS_CTRL, mac_sys_ctrl);
rt2800_vco_calibration(rt2x00dev);
@@ -5887,18 +5898,33 @@ static int rt2800_init_registers(struct
} else if (rt2x00_rt(rt2x00dev, RT5350)) {
rt2800_register_write(rt2x00dev, TX_SW_CFG0, 0x00000404);
} else if (rt2x00_rt(rt2x00dev, RT6352)) {
- rt2800_register_write(rt2x00dev, TX_SW_CFG0, 0x00000401);
- rt2800_register_write(rt2x00dev, TX_SW_CFG1, 0x000C0000);
- rt2800_register_write(rt2x00dev, TX_SW_CFG2, 0x00000000);
- rt2800_register_write(rt2x00dev, TX_ALC_VGA3, 0x00000000);
- rt2800_register_write(rt2x00dev, TX0_BB_GAIN_ATTEN, 0x0);
- rt2800_register_write(rt2x00dev, TX1_BB_GAIN_ATTEN, 0x0);
- rt2800_register_write(rt2x00dev, TX0_RF_GAIN_ATTEN, 0x6C6C666C);
- rt2800_register_write(rt2x00dev, TX1_RF_GAIN_ATTEN, 0x6C6C666C);
- rt2800_register_write(rt2x00dev, TX0_RF_GAIN_CORRECT,
- 0x3630363A);
- rt2800_register_write(rt2x00dev, TX1_RF_GAIN_CORRECT,
- 0x3630363A);
+ if (rt2800_hw_get_chipver(rt2x00dev) <= 1) {
+ rt2800_register_write(rt2x00dev, TX_ALC_VGA3,
+ 0x00000000);
+ rt2800_register_write(rt2x00dev, BB_PA_MODE_CFG0,
+ 0x000055FF);
+ rt2800_register_write(rt2x00dev, BB_PA_MODE_CFG1,
+ 0x00550055);
+ rt2800_register_write(rt2x00dev, RF_PA_MODE_CFG0,
+ 0x000055FF);
+ rt2800_register_write(rt2x00dev, RF_PA_MODE_CFG1,
+ 0x00550055);
+ } else {
+ rt2800_register_write(rt2x00dev, TX_SW_CFG0, 0x00000401);
+ rt2800_register_write(rt2x00dev, TX_SW_CFG1, 0x000C0000);
+ rt2800_register_write(rt2x00dev, TX_SW_CFG2, 0x00000000);
+ rt2800_register_write(rt2x00dev, TX_ALC_VGA3, 0x00000000);
+ rt2800_register_write(rt2x00dev, TX0_BB_GAIN_ATTEN, 0x0);
+ rt2800_register_write(rt2x00dev, TX1_BB_GAIN_ATTEN, 0x0);
+ rt2800_register_write(rt2x00dev, TX0_RF_GAIN_ATTEN,
+ 0x6C6C666C);
+ rt2800_register_write(rt2x00dev, TX1_RF_GAIN_ATTEN,
+ 0x6C6C666C);
+ rt2800_register_write(rt2x00dev, TX0_RF_GAIN_CORRECT,
+ 0x3630363A);
+ rt2800_register_write(rt2x00dev, TX1_RF_GAIN_CORRECT,
+ 0x3630363A);
+ }
reg = rt2800_register_read(rt2x00dev, TX_ALC_CFG_1);
rt2x00_set_field32(&reg, TX_ALC_CFG_1_ROS_BUSY_EN, 0);
rt2800_register_write(rt2x00dev, TX_ALC_CFG_1, reg);
@@ -7042,14 +7068,16 @@ static void rt2800_init_bbp_6352(struct
rt2800_bbp_write(rt2x00dev, 188, 0x00);
rt2800_bbp_write(rt2x00dev, 189, 0x00);
- rt2800_bbp_write(rt2x00dev, 91, 0x06);
- rt2800_bbp_write(rt2x00dev, 92, 0x04);
- rt2800_bbp_write(rt2x00dev, 93, 0x54);
- rt2800_bbp_write(rt2x00dev, 99, 0x50);
- rt2800_bbp_write(rt2x00dev, 148, 0x84);
- rt2800_bbp_write(rt2x00dev, 167, 0x80);
- rt2800_bbp_write(rt2x00dev, 178, 0xFF);
- rt2800_bbp_write(rt2x00dev, 106, 0x13);
+ if (rt2800_hw_get_chipver(rt2x00dev) > 1) {
+ rt2800_bbp_write(rt2x00dev, 91, 0x06);
+ rt2800_bbp_write(rt2x00dev, 92, 0x04);
+ rt2800_bbp_write(rt2x00dev, 93, 0x54);
+ rt2800_bbp_write(rt2x00dev, 99, 0x50);
+ rt2800_bbp_write(rt2x00dev, 148, 0x84);
+ rt2800_bbp_write(rt2x00dev, 167, 0x80);
+ rt2800_bbp_write(rt2x00dev, 178, 0xFF);
+ rt2800_bbp_write(rt2x00dev, 106, 0x13);
+ }
/* BBP for G band GLRT function (BBP_128 ~ BBP_221) */
rt2800_bbp_glrt_write(rt2x00dev, 0, 0x00);
@@ -10388,31 +10416,36 @@ static void rt2800_init_rfcsr_6352(struc
rt2800_rfcsr_write(rt2x00dev, 42, 0x5B);
rt2800_rfcsr_write(rt2x00dev, 43, 0x00);
- rt2800_rfcsr_write(rt2x00dev, 11, 0x21);
- if (rt2800_clk_is_20mhz(rt2x00dev))
- rt2800_rfcsr_write(rt2x00dev, 13, 0x03);
- else
- rt2800_rfcsr_write(rt2x00dev, 13, 0x00);
- rt2800_rfcsr_write(rt2x00dev, 14, 0x7C);
- rt2800_rfcsr_write(rt2x00dev, 16, 0x80);
- rt2800_rfcsr_write(rt2x00dev, 17, 0x99);
- rt2800_rfcsr_write(rt2x00dev, 18, 0x99);
- rt2800_rfcsr_write(rt2x00dev, 19, 0x09);
- rt2800_rfcsr_write(rt2x00dev, 20, 0x50);
- rt2800_rfcsr_write(rt2x00dev, 21, 0xB0);
- rt2800_rfcsr_write(rt2x00dev, 22, 0x00);
- rt2800_rfcsr_write(rt2x00dev, 23, 0x06);
- rt2800_rfcsr_write(rt2x00dev, 24, 0x00);
- rt2800_rfcsr_write(rt2x00dev, 25, 0x00);
- rt2800_rfcsr_write(rt2x00dev, 26, 0x5D);
- rt2800_rfcsr_write(rt2x00dev, 27, 0x00);
- rt2800_rfcsr_write(rt2x00dev, 28, 0x61);
- rt2800_rfcsr_write(rt2x00dev, 29, 0xB5);
- rt2800_rfcsr_write(rt2x00dev, 43, 0x02);
-
- rt2800_rfcsr_write(rt2x00dev, 28, 0x62);
- rt2800_rfcsr_write(rt2x00dev, 29, 0xAD);
- rt2800_rfcsr_write(rt2x00dev, 39, 0x80);
+ if (rt2800_hw_get_chipver(rt2x00dev) > 1) {
+ rt2800_rfcsr_write(rt2x00dev, 11, 0x21);
+ if (rt2800_clk_is_20mhz(rt2x00dev))
+ rt2800_rfcsr_write(rt2x00dev, 13, 0x03);
+ else
+ rt2800_rfcsr_write(rt2x00dev, 13, 0x00);
+ rt2800_rfcsr_write(rt2x00dev, 14, 0x7C);
+ rt2800_rfcsr_write(rt2x00dev, 16, 0x80);
+ rt2800_rfcsr_write(rt2x00dev, 17, 0x99);
+ rt2800_rfcsr_write(rt2x00dev, 18, 0x99);
+ rt2800_rfcsr_write(rt2x00dev, 19, 0x09);
+ rt2800_rfcsr_write(rt2x00dev, 20, 0x50);
+ rt2800_rfcsr_write(rt2x00dev, 21, 0xB0);
+ rt2800_rfcsr_write(rt2x00dev, 22, 0x00);
+ rt2800_rfcsr_write(rt2x00dev, 23, 0x06);
+ rt2800_rfcsr_write(rt2x00dev, 24, 0x00);
+ rt2800_rfcsr_write(rt2x00dev, 25, 0x00);
+ rt2800_rfcsr_write(rt2x00dev, 26, 0x5D);
+ rt2800_rfcsr_write(rt2x00dev, 27, 0x00);
+ rt2800_rfcsr_write(rt2x00dev, 28, 0x61);
+ rt2800_rfcsr_write(rt2x00dev, 29, 0xB5);
+ rt2800_rfcsr_write(rt2x00dev, 43, 0x02);
+ }
+
+ if (rt2800_hw_get_chipver(rt2x00dev) > 1 &&
+ rt2800_hw_get_chipeco(rt2x00dev) >= 2) {
+ rt2800_rfcsr_write(rt2x00dev, 28, 0x62);
+ rt2800_rfcsr_write(rt2x00dev, 29, 0xAD);
+ rt2800_rfcsr_write(rt2x00dev, 39, 0x80);
+ }
/* Initialize RF channel register to default value */
rt2800_rfcsr_write_chanreg(rt2x00dev, 0, 0x03);
@@ -10478,63 +10511,71 @@ static void rt2800_init_rfcsr_6352(struc
rt2800_rfcsr_write_bank(rt2x00dev, 6, 45, 0xC5);
- rt2800_rfcsr_write_chanreg(rt2x00dev, 9, 0x47);
- rt2800_rfcsr_write_chanreg(rt2x00dev, 10, 0x71);
- rt2800_rfcsr_write_chanreg(rt2x00dev, 11, 0x33);
- rt2800_rfcsr_write_chanreg(rt2x00dev, 14, 0x0E);
- rt2800_rfcsr_write_chanreg(rt2x00dev, 17, 0x23);
- rt2800_rfcsr_write_chanreg(rt2x00dev, 19, 0xA4);
- rt2800_rfcsr_write_chanreg(rt2x00dev, 20, 0x02);
- rt2800_rfcsr_write_chanreg(rt2x00dev, 21, 0x12);
- rt2800_rfcsr_write_chanreg(rt2x00dev, 28, 0x1C);
- rt2800_rfcsr_write_chanreg(rt2x00dev, 29, 0xEB);
- rt2800_rfcsr_write_chanreg(rt2x00dev, 32, 0x7D);
- rt2800_rfcsr_write_chanreg(rt2x00dev, 34, 0xD6);
- rt2800_rfcsr_write_chanreg(rt2x00dev, 36, 0x08);
- rt2800_rfcsr_write_chanreg(rt2x00dev, 38, 0xB4);
- rt2800_rfcsr_write_chanreg(rt2x00dev, 43, 0xD3);
- rt2800_rfcsr_write_chanreg(rt2x00dev, 44, 0xB3);
- rt2800_rfcsr_write_chanreg(rt2x00dev, 45, 0xD5);
- rt2800_rfcsr_write_chanreg(rt2x00dev, 46, 0x27);
- rt2800_rfcsr_write_bank(rt2x00dev, 4, 47, 0x67);
- rt2800_rfcsr_write_bank(rt2x00dev, 6, 47, 0x69);
- rt2800_rfcsr_write_chanreg(rt2x00dev, 48, 0xFF);
- rt2800_rfcsr_write_bank(rt2x00dev, 4, 54, 0x27);
- rt2800_rfcsr_write_bank(rt2x00dev, 6, 54, 0x20);
- rt2800_rfcsr_write_chanreg(rt2x00dev, 55, 0x66);
- rt2800_rfcsr_write_chanreg(rt2x00dev, 56, 0xFF);
- rt2800_rfcsr_write_chanreg(rt2x00dev, 57, 0x1C);
- rt2800_rfcsr_write_chanreg(rt2x00dev, 58, 0x20);
- rt2800_rfcsr_write_chanreg(rt2x00dev, 59, 0x6B);
- rt2800_rfcsr_write_chanreg(rt2x00dev, 60, 0xF7);
- rt2800_rfcsr_write_chanreg(rt2x00dev, 61, 0x09);
-
- rt2800_rfcsr_write_chanreg(rt2x00dev, 10, 0x51);
- rt2800_rfcsr_write_chanreg(rt2x00dev, 14, 0x06);
- rt2800_rfcsr_write_chanreg(rt2x00dev, 19, 0xA7);
- rt2800_rfcsr_write_chanreg(rt2x00dev, 28, 0x2C);
- rt2800_rfcsr_write_chanreg(rt2x00dev, 55, 0x64);
- rt2800_rfcsr_write_chanreg(rt2x00dev, 8, 0x51);
- rt2800_rfcsr_write_chanreg(rt2x00dev, 9, 0x36);
- rt2800_rfcsr_write_chanreg(rt2x00dev, 11, 0x53);
- rt2800_rfcsr_write_chanreg(rt2x00dev, 14, 0x16);
-
- rt2800_rfcsr_write_chanreg(rt2x00dev, 47, 0x6C);
- rt2800_rfcsr_write_chanreg(rt2x00dev, 48, 0xFC);
- rt2800_rfcsr_write_chanreg(rt2x00dev, 49, 0x1F);
- rt2800_rfcsr_write_chanreg(rt2x00dev, 54, 0x27);
- rt2800_rfcsr_write_chanreg(rt2x00dev, 55, 0x66);
- rt2800_rfcsr_write_chanreg(rt2x00dev, 59, 0x6B);
-
- /* Initialize RF channel register for DRQFN */
- rt2800_rfcsr_write_chanreg(rt2x00dev, 43, 0xD3);
- rt2800_rfcsr_write_chanreg(rt2x00dev, 44, 0xE3);
- rt2800_rfcsr_write_chanreg(rt2x00dev, 45, 0xE5);
- rt2800_rfcsr_write_chanreg(rt2x00dev, 47, 0x28);
- rt2800_rfcsr_write_chanreg(rt2x00dev, 55, 0x68);
- rt2800_rfcsr_write_chanreg(rt2x00dev, 56, 0xF7);
- rt2800_rfcsr_write_chanreg(rt2x00dev, 58, 0x02);
- rt2800_rfcsr_write_chanreg(rt2x00dev, 60, 0xC7);
+ if (rt2800_hw_get_chipver(rt2x00dev) > 1) {
+ rt2800_rfcsr_write_chanreg(rt2x00dev, 9, 0x47);
+ rt2800_rfcsr_write_chanreg(rt2x00dev, 10, 0x71);
+ rt2800_rfcsr_write_chanreg(rt2x00dev, 11, 0x33);
+ rt2800_rfcsr_write_chanreg(rt2x00dev, 14, 0x0E);
+ rt2800_rfcsr_write_chanreg(rt2x00dev, 17, 0x23);
+ rt2800_rfcsr_write_chanreg(rt2x00dev, 19, 0xA4);
+ rt2800_rfcsr_write_chanreg(rt2x00dev, 20, 0x02);
+ rt2800_rfcsr_write_chanreg(rt2x00dev, 21, 0x12);
+ rt2800_rfcsr_write_chanreg(rt2x00dev, 28, 0x1C);
+ rt2800_rfcsr_write_chanreg(rt2x00dev, 29, 0xEB);
+ rt2800_rfcsr_write_chanreg(rt2x00dev, 32, 0x7D);
+ rt2800_rfcsr_write_chanreg(rt2x00dev, 34, 0xD6);
+ rt2800_rfcsr_write_chanreg(rt2x00dev, 36, 0x08);
+ rt2800_rfcsr_write_chanreg(rt2x00dev, 38, 0xB4);
+ rt2800_rfcsr_write_chanreg(rt2x00dev, 43, 0xD3);
+ rt2800_rfcsr_write_chanreg(rt2x00dev, 44, 0xB3);
+ rt2800_rfcsr_write_chanreg(rt2x00dev, 45, 0xD5);
+ rt2800_rfcsr_write_chanreg(rt2x00dev, 46, 0x27);
+ rt2800_rfcsr_write_bank(rt2x00dev, 4, 47, 0x67);
+ rt2800_rfcsr_write_bank(rt2x00dev, 6, 47, 0x69);
+ rt2800_rfcsr_write_chanreg(rt2x00dev, 48, 0xFF);
+ rt2800_rfcsr_write_bank(rt2x00dev, 4, 54, 0x27);
+ rt2800_rfcsr_write_bank(rt2x00dev, 6, 54, 0x20);
+ rt2800_rfcsr_write_chanreg(rt2x00dev, 55, 0x66);
+ rt2800_rfcsr_write_chanreg(rt2x00dev, 56, 0xFF);
+ rt2800_rfcsr_write_chanreg(rt2x00dev, 57, 0x1C);
+ rt2800_rfcsr_write_chanreg(rt2x00dev, 58, 0x20);
+ rt2800_rfcsr_write_chanreg(rt2x00dev, 59, 0x6B);
+ rt2800_rfcsr_write_chanreg(rt2x00dev, 60, 0xF7);
+ rt2800_rfcsr_write_chanreg(rt2x00dev, 61, 0x09);
+ }
+
+ if (rt2800_hw_get_chipver(rt2x00dev) > 1 &&
+ rt2800_hw_get_chipeco(rt2x00dev) >= 2) {
+ rt2800_rfcsr_write_chanreg(rt2x00dev, 10, 0x51);
+ rt2800_rfcsr_write_chanreg(rt2x00dev, 14, 0x06);
+ rt2800_rfcsr_write_chanreg(rt2x00dev, 19, 0xA7);
+ rt2800_rfcsr_write_chanreg(rt2x00dev, 28, 0x2C);
+ rt2800_rfcsr_write_chanreg(rt2x00dev, 55, 0x64);
+ rt2800_rfcsr_write_chanreg(rt2x00dev, 8, 0x51);
+ rt2800_rfcsr_write_chanreg(rt2x00dev, 9, 0x36);
+ rt2800_rfcsr_write_chanreg(rt2x00dev, 11, 0x53);
+ rt2800_rfcsr_write_chanreg(rt2x00dev, 14, 0x16);
+
+ rt2800_rfcsr_write_chanreg(rt2x00dev, 47, 0x6C);
+ rt2800_rfcsr_write_chanreg(rt2x00dev, 48, 0xFC);
+ rt2800_rfcsr_write_chanreg(rt2x00dev, 49, 0x1F);
+ rt2800_rfcsr_write_chanreg(rt2x00dev, 54, 0x27);
+ rt2800_rfcsr_write_chanreg(rt2x00dev, 55, 0x66);
+ rt2800_rfcsr_write_chanreg(rt2x00dev, 59, 0x6B);
+ }
+
+ if (rt2800_hw_get_chippkg(rt2x00dev) == 0 &&
+ rt2800_hw_get_chipver(rt2x00dev) == 1) {
+ /* Initialize RF channel register for DRQFN */
+ rt2800_rfcsr_write_chanreg(rt2x00dev, 43, 0xD3);
+ rt2800_rfcsr_write_chanreg(rt2x00dev, 44, 0xE3);
+ rt2800_rfcsr_write_chanreg(rt2x00dev, 45, 0xE5);
+ rt2800_rfcsr_write_chanreg(rt2x00dev, 47, 0x28);
+ rt2800_rfcsr_write_chanreg(rt2x00dev, 55, 0x68);
+ rt2800_rfcsr_write_chanreg(rt2x00dev, 56, 0xF7);
+ rt2800_rfcsr_write_chanreg(rt2x00dev, 58, 0x02);
+ rt2800_rfcsr_write_chanreg(rt2x00dev, 60, 0xC7);
+ }
/* Initialize RF DC calibration register to default value */
rt2800_rfcsr_write_dccal(rt2x00dev, 0, 0x47);
@@ -10597,12 +10638,17 @@ static void rt2800_init_rfcsr_6352(struc
rt2800_rfcsr_write_dccal(rt2x00dev, 62, 0x00);
rt2800_rfcsr_write_dccal(rt2x00dev, 63, 0x00);
- rt2800_rfcsr_write_dccal(rt2x00dev, 3, 0x08);
- rt2800_rfcsr_write_dccal(rt2x00dev, 4, 0x04);
- rt2800_rfcsr_write_dccal(rt2x00dev, 5, 0x20);
+ if (rt2800_hw_get_chipver(rt2x00dev) > 1) {
+ rt2800_rfcsr_write_dccal(rt2x00dev, 3, 0x08);
+ rt2800_rfcsr_write_dccal(rt2x00dev, 4, 0x04);
+ rt2800_rfcsr_write_dccal(rt2x00dev, 5, 0x20);
+ }
- rt2800_rfcsr_write_dccal(rt2x00dev, 5, 0x00);
- rt2800_rfcsr_write_dccal(rt2x00dev, 17, 0x7C);
+ if (rt2800_hw_get_chipver(rt2x00dev) > 1 &&
+ rt2800_hw_get_chipeco(rt2x00dev) >= 2) {
+ rt2800_rfcsr_write_dccal(rt2x00dev, 5, 0x00);
+ rt2800_rfcsr_write_dccal(rt2x00dev, 17, 0x7C);
+ }
rt2800_r_calibration(rt2x00dev);
rt2800_rf_self_txdc_cal(rt2x00dev);

View File

@ -0,0 +1,183 @@
--- a/drivers/net/wireless/ralink/rt2x00/rt2800lib.c
+++ b/drivers/net/wireless/ralink/rt2x00/rt2800lib.c
@@ -1238,6 +1238,8 @@ void rt2800_watchdog(struct rt2x00_dev *
if (test_bit(DEVICE_STATE_SCANNING, &rt2x00dev->flags))
return;
+ rt2800_update_survey(rt2x00dev);
+
queue_for_each(rt2x00dev, queue) {
switch (queue->qid) {
case QID_AC_VO:
@@ -1274,6 +1276,18 @@ void rt2800_watchdog(struct rt2x00_dev *
}
EXPORT_SYMBOL_GPL(rt2800_watchdog);
+void rt2800_update_survey(struct rt2x00_dev *rt2x00dev)
+{
+ struct ieee80211_channel *chan = rt2x00dev->hw->conf.chandef.chan;
+ struct rt2x00_chan_survey *chan_survey =
+ &rt2x00dev->chan_survey[chan->hw_value];
+
+ chan_survey->time_idle += rt2800_register_read(rt2x00dev, CH_IDLE_STA);
+ chan_survey->time_busy += rt2800_register_read(rt2x00dev, CH_BUSY_STA);
+ chan_survey->time_ext_busy += rt2800_register_read(rt2x00dev, CH_BUSY_STA_SEC);
+}
+EXPORT_SYMBOL_GPL(rt2800_update_survey);
+
static unsigned int rt2800_hw_beacon_base(struct rt2x00_dev *rt2x00dev,
unsigned int index)
{
@@ -12199,26 +12213,30 @@ int rt2800_get_survey(struct ieee80211_h
{
struct rt2x00_dev *rt2x00dev = hw->priv;
struct ieee80211_conf *conf = &hw->conf;
- u32 idle, busy, busy_ext;
+ struct rt2x00_chan_survey *chan_survey =
+ &rt2x00dev->chan_survey[idx];
+ enum nl80211_band band = NL80211_BAND_2GHZ;
- if (idx != 0)
+ if (idx >= rt2x00dev->bands[band].n_channels) {
+ idx -= rt2x00dev->bands[band].n_channels;
+ band = NL80211_BAND_5GHZ;
+ }
+
+ if (idx >= rt2x00dev->bands[band].n_channels)
return -ENOENT;
- survey->channel = conf->chandef.chan;
+ if (idx == 0)
+ rt2800_update_survey(rt2x00dev);
- idle = rt2800_register_read(rt2x00dev, CH_IDLE_STA);
- busy = rt2800_register_read(rt2x00dev, CH_BUSY_STA);
- busy_ext = rt2800_register_read(rt2x00dev, CH_BUSY_STA_SEC);
-
- if (idle || busy) {
- survey->filled = SURVEY_INFO_TIME |
- SURVEY_INFO_TIME_BUSY |
- SURVEY_INFO_TIME_EXT_BUSY;
-
- survey->time = (idle + busy) / 1000;
- survey->time_busy = busy / 1000;
- survey->time_ext_busy = busy_ext / 1000;
- }
+ survey->channel = &rt2x00dev->bands[band].channels[idx];
+
+ survey->filled = SURVEY_INFO_TIME |
+ SURVEY_INFO_TIME_BUSY |
+ SURVEY_INFO_TIME_EXT_BUSY;
+
+ survey->time = div_u64(chan_survey->time_idle + chan_survey->time_busy, 1000);
+ survey->time_busy = div_u64(chan_survey->time_busy, 1000);
+ survey->time_ext_busy = div_u64(chan_survey->time_ext_busy, 1000);
if (!(hw->conf.flags & IEEE80211_CONF_OFFCHANNEL))
survey->filled |= SURVEY_INFO_IN_USE;
--- a/drivers/net/wireless/ralink/rt2x00/rt2800lib.h
+++ b/drivers/net/wireless/ralink/rt2x00/rt2800lib.h
@@ -243,6 +243,7 @@ bool rt2800_txstatus_timeout(struct rt2x
bool rt2800_txstatus_pending(struct rt2x00_dev *rt2x00dev);
void rt2800_watchdog(struct rt2x00_dev *rt2x00dev);
+void rt2800_update_survey(struct rt2x00_dev *rt2x00dev);
void rt2800_write_beacon(struct queue_entry *entry, struct txentry_desc *txdesc);
void rt2800_clear_beacon(struct queue_entry *entry);
--- a/drivers/net/wireless/ralink/rt2x00/rt2800pci.c
+++ b/drivers/net/wireless/ralink/rt2x00/rt2800pci.c
@@ -360,6 +360,7 @@ static const struct rt2x00lib_ops rt2800
.gain_calibration = rt2800_gain_calibration,
.vco_calibration = rt2800_vco_calibration,
.watchdog = rt2800_watchdog,
+ .update_survey = rt2800_update_survey,
.start_queue = rt2800mmio_start_queue,
.kick_queue = rt2800mmio_kick_queue,
.stop_queue = rt2800mmio_stop_queue,
--- a/drivers/net/wireless/ralink/rt2x00/rt2800soc.c
+++ b/drivers/net/wireless/ralink/rt2x00/rt2800soc.c
@@ -214,6 +214,7 @@ static const struct rt2x00lib_ops rt2800
.gain_calibration = rt2800_gain_calibration,
.vco_calibration = rt2800_vco_calibration,
.watchdog = rt2800_watchdog,
+ .update_survey = rt2800_update_survey,
.start_queue = rt2800mmio_start_queue,
.kick_queue = rt2800mmio_kick_queue,
.stop_queue = rt2800mmio_stop_queue,
--- a/drivers/net/wireless/ralink/rt2x00/rt2x00.h
+++ b/drivers/net/wireless/ralink/rt2x00/rt2x00.h
@@ -183,6 +183,15 @@ struct rf_channel {
};
/*
+ * Information structure for channel survey.
+ */
+struct rt2x00_chan_survey {
+ u64 time_idle;
+ u64 time_busy;
+ u64 time_ext_busy;
+};
+
+/*
* Channel information structure
*/
struct channel_info {
@@ -567,6 +576,7 @@ struct rt2x00lib_ops {
* Data queue handlers.
*/
void (*watchdog) (struct rt2x00_dev *rt2x00dev);
+ void (*update_survey) (struct rt2x00_dev *rt2x00dev);
void (*start_queue) (struct data_queue *queue);
void (*kick_queue) (struct data_queue *queue);
void (*stop_queue) (struct data_queue *queue);
@@ -755,6 +765,7 @@ struct rt2x00_dev {
*/
struct ieee80211_hw *hw;
struct ieee80211_supported_band bands[NUM_NL80211_BANDS];
+ struct rt2x00_chan_survey *chan_survey;
enum nl80211_band curr_band;
int curr_freq;
--- a/drivers/net/wireless/ralink/rt2x00/rt2x00dev.c
+++ b/drivers/net/wireless/ralink/rt2x00/rt2x00dev.c
@@ -1057,6 +1057,12 @@ static int rt2x00lib_probe_hw_modes(stru
if (!rates)
goto exit_free_channels;
+ rt2x00dev->chan_survey =
+ kcalloc(spec->num_channels, sizeof(struct rt2x00_chan_survey),
+ GFP_KERNEL);
+ if (!rt2x00dev->chan_survey)
+ goto exit_free_rates;
+
/*
* Initialize Rate list.
*/
@@ -1108,6 +1114,8 @@ static int rt2x00lib_probe_hw_modes(stru
return 0;
+ exit_free_rates:
+ kfree(rates);
exit_free_channels:
kfree(channels);
rt2x00_err(rt2x00dev, "Allocation ieee80211 modes failed\n");
--- a/drivers/net/wireless/ralink/rt2x00/rt2x00mac.c
+++ b/drivers/net/wireless/ralink/rt2x00/rt2x00mac.c
@@ -317,6 +317,15 @@ int rt2x00mac_config(struct ieee80211_hw
return 0;
/*
+ * To provide correct survey data for survey-based ACS algorithm
+ * we have to save survey data for current channel before switching.
+ */
+ if (rt2x00dev->ops->lib->update_survey &&
+ (changed & IEEE80211_CONF_CHANGE_CHANNEL)) {
+ rt2x00dev->ops->lib->update_survey(rt2x00dev);
+ }
+
+ /*
* Some configuration parameters (e.g. channel and antenna values) can
* only be set when the radio is enabled, but do require the RX to
* be off. During this period we should keep link tuning enabled,

View File

@ -1,31 +0,0 @@
From e1f04bf9d38633f0bf9d041089366fea0ad22623 Mon Sep 17 00:00:00 2001
From: Hauke Mehrtens <hauke@hauke-m.de>
Date: Thu, 21 May 2020 19:50:05 +0200
Subject: [PATCH] wireless: Use linux/stddef.h instead of stddef.h
When compiling inside the kernel include linux/stddef.h instead of
stddef.h. When I compile this header file in backports for power PC I
run into a conflict with ptrdiff_t. I was unable to reproduce this in
mainline kernel. I still would like to fix this problem in the kernel.
Fixes: 6989310f5d43 ("wireless: Use offsetof instead of custom macro.")
Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
---
include/uapi/linux/wireless.h | 6 +++++-
1 file changed, 5 insertions(+), 1 deletion(-)
--- a/include/uapi/linux/wireless.h
+++ b/include/uapi/linux/wireless.h
@@ -74,7 +74,11 @@
#include <linux/socket.h> /* for "struct sockaddr" et al */
#include <linux/if.h> /* for IFNAMSIZ and co... */
-#include <stddef.h> /* for offsetof */
+#ifdef __KERNEL__
+# include <linux/stddef.h> /* for offsetof */
+#else
+# include <stddef.h> /* for offsetof */
+#endif
/***************************** VERSION *****************************/
/*

View File

@ -8,7 +8,7 @@
wpa.o \
scan.o offchannel.o \
ht.o agg-tx.o agg-rx.o \
@@ -18,8 +17,8 @@ mac80211-y := \
@@ -19,8 +18,8 @@ mac80211-y := \
rate.o \
michael.o \
tkip.o \
@ -64,7 +64,7 @@
- aead_request_set_ad(aead_req, sg[0].length);
-
- crypto_aead_encrypt(aead_req);
- kzfree(aead_req);
- kfree_sensitive(aead_req);
-
- return 0;
-}
@ -99,7 +99,7 @@
- aead_request_set_ad(aead_req, sg[0].length);
-
- err = crypto_aead_decrypt(aead_req);
- kzfree(aead_req);
- kfree_sensitive(aead_req);
-
- return err;
-}
@ -654,7 +654,7 @@
- depends on CRYPTO_GCM
depends on CRYPTO_CMAC
depends on CRC32
---help---
help
--- a/net/mac80211/aes_gmac.h
+++ b/net/mac80211/aes_gmac.h
@@ -12,10 +12,22 @@
@ -687,7 +687,7 @@
#endif /* AES_GMAC_H */
--- a/net/mac80211/key.h
+++ b/net/mac80211/key.h
@@ -88,7 +88,7 @@ struct ieee80211_key {
@@ -89,7 +89,7 @@ struct ieee80211_key {
* Management frames.
*/
u8 rx_pn[IEEE80211_NUM_TIDS + 1][IEEE80211_CCMP_PN_LEN];

View File

@ -2,11 +2,11 @@ Used for AP+STA support in OpenWrt - preserve AP mode keys across STA reconnects
--- a/net/mac80211/cfg.c
+++ b/net/mac80211/cfg.c
@@ -1172,7 +1172,6 @@ static int ieee80211_stop_ap(struct wiph
@@ -1288,7 +1288,6 @@ static int ieee80211_stop_ap(struct wiph
sdata->vif.bss_conf.ftmr_params = NULL;
__sta_info_flush(sdata, true);
- ieee80211_free_keys(sdata, true);
sdata->vif.bss_conf.enable_beacon = false;
sdata->vif.bss_conf.ssid_len = 0;
sdata->beacon_rate_set = false;

View File

@ -21,7 +21,7 @@ Disable FILS support, since it pulls in crypto hash support
* FILS AEAD for (Re)Association Request/Response frames
--- a/net/mac80211/main.c
+++ b/net/mac80211/main.c
@@ -571,7 +571,7 @@ struct ieee80211_hw *ieee80211_alloc_hw_
@@ -591,7 +591,7 @@ struct ieee80211_hw *ieee80211_alloc_hw_
NL80211_FEATURE_MAC_ON_CREATE |
NL80211_FEATURE_USERSPACE_MPM |
NL80211_FEATURE_FULL_AP_CLIENT_STATE;

View File

@ -11,14 +11,13 @@ Signed-off-by: Felix Fietkau <nbd@nbd.name>
--- a/net/mac80211/aes_cmac.c
+++ b/net/mac80211/aes_cmac.c
@@ -19,50 +19,126 @@
@@ -19,67 +19,151 @@
#define CMAC_TLEN_256 16 /* CMAC TLen = 128 bits (16 octets) */
#define AAD_LEN 20
-static const u8 zero[CMAC_TLEN_256];
-void ieee80211_aes_cmac(struct crypto_shash *tfm, const u8 *aad,
- const u8 *data, size_t data_len, u8 *mic)
+void gf_mulx(u8 *pad)
+{
+ int i, carry;
@ -34,9 +33,7 @@ Signed-off-by: Felix Fietkau <nbd@nbd.name>
+void aes_cmac_vector(struct crypto_cipher *tfm, size_t num_elem,
+ const u8 *addr[], const size_t *len, u8 *mac,
+ size_t mac_len)
{
- SHASH_DESC_ON_STACK(desc, tfm);
- u8 out[AES_BLOCK_SIZE];
+{
+ u8 cbc[AES_BLOCK_SIZE], pad[AES_BLOCK_SIZE];
+ const u8 *pos, *end;
+ size_t i, e, left, total_len;
@ -88,30 +85,48 @@ Signed-off-by: Felix Fietkau <nbd@nbd.name>
+ crypto_cipher_encrypt_one(tfm, pad, pad);
+ memcpy(mac, pad, mac_len);
+}
+
+
+void ieee80211_aes_cmac(struct crypto_cipher *tfm, const u8 *aad,
const u8 *data, size_t data_len, u8 *mic)
{
- SHASH_DESC_ON_STACK(desc, tfm);
- u8 out[AES_BLOCK_SIZE];
+ const u8 *addr[4];
+ size_t len[4];
+ u8 zero[CMAC_TLEN];
const __le16 *fc;
- desc->tfm = tfm;
-
- crypto_shash_init(desc);
- crypto_shash_update(desc, aad, AAD_LEN);
- crypto_shash_update(desc, data, data_len - CMAC_TLEN);
- crypto_shash_finup(desc, zero, CMAC_TLEN, out);
+void ieee80211_aes_cmac(struct crypto_cipher *tfm, const u8 *aad,
+ const u8 *data, size_t data_len, u8 *mic)
+{
+ const u8 *addr[3];
+ size_t len[3];
+ u8 zero[CMAC_TLEN];
+
+ memset(zero, 0, CMAC_TLEN);
+ addr[0] = aad;
+ len[0] = AAD_LEN;
+ addr[1] = data;
+ len[1] = data_len - CMAC_TLEN;
+ addr[2] = zero;
+ len[2] = CMAC_TLEN;
fc = (const __le16 *)aad;
if (ieee80211_is_beacon(*fc)) {
/* mask Timestamp field to zero */
- crypto_shash_update(desc, zero, 8);
- crypto_shash_update(desc, data + 8, data_len - 8 - CMAC_TLEN);
+ addr[1] = zero;
+ len[1] = 8;
+ addr[2] = data + 8;
+ len[2] = data_len - 8 - CMAC_TLEN;
+ addr[3] = zero;
+ len[3] = CMAC_TLEN;
+ aes_cmac_vector(tfm, 4, addr, len, mic, CMAC_TLEN);
} else {
- crypto_shash_update(desc, data, data_len - CMAC_TLEN);
+ addr[1] = data;
+ len[1] = data_len - CMAC_TLEN;
+ addr[2] = zero;
+ len[2] = CMAC_TLEN;
+ aes_cmac_vector(tfm, 3, addr, len, mic, CMAC_TLEN);
}
- crypto_shash_finup(desc, zero, CMAC_TLEN, out);
-
- memcpy(mic, out, CMAC_TLEN);
+ aes_cmac_vector(tfm, 3, addr, len, mic, CMAC_TLEN);
}
-void ieee80211_aes_cmac_256(struct crypto_shash *tfm, const u8 *aad,
@ -119,25 +134,41 @@ Signed-off-by: Felix Fietkau <nbd@nbd.name>
const u8 *data, size_t data_len, u8 *mic)
{
- SHASH_DESC_ON_STACK(desc, tfm);
+ const u8 *addr[3];
+ size_t len[3];
+ const u8 *addr[4];
+ size_t len[4];
+ u8 zero[CMAC_TLEN_256];
+
+ memset(zero, 0, CMAC_TLEN_256);
+ addr[0] = aad;
+ len[0] = AAD_LEN;
+ addr[1] = data;
+ len[1] = data_len - CMAC_TLEN_256;
+ addr[2] = zero;
+ len[2] = CMAC_TLEN_256;
const __le16 *fc;
- desc->tfm = tfm;
-
- crypto_shash_init(desc);
- crypto_shash_update(desc, aad, AAD_LEN);
- crypto_shash_update(desc, data, data_len - CMAC_TLEN_256);
+ memset(zero, 0, CMAC_TLEN_256);
+ addr[0] = aad;
+ len[0] = AAD_LEN;
+ addr[1] = data;
fc = (const __le16 *)aad;
if (ieee80211_is_beacon(*fc)) {
/* mask Timestamp field to zero */
- crypto_shash_update(desc, zero, 8);
- crypto_shash_update(desc, data + 8,
- data_len - 8 - CMAC_TLEN_256);
+ addr[1] = zero;
+ len[1] = 8;
+ addr[2] = data + 8;
+ len[2] = data_len - 8 - CMAC_TLEN_256;
+ addr[3] = zero;
+ len[3] = CMAC_TLEN_256;
+ aes_cmac_vector(tfm, 4, addr, len, mic, CMAC_TLEN_256);
} else {
- crypto_shash_update(desc, data, data_len - CMAC_TLEN_256);
+ addr[1] = data;
+ len[1] = data_len - CMAC_TLEN_256;
+ addr[2] = zero;
+ len[2] = CMAC_TLEN_256;
+ aes_cmac_vector(tfm, 3, addr, len, mic, CMAC_TLEN_256);
}
- crypto_shash_finup(desc, zero, CMAC_TLEN_256, mic);
+ aes_cmac_vector(tfm, 3, addr, len, mic, CMAC_TLEN_256);
}
-struct crypto_shash *ieee80211_aes_cmac_key_setup(const u8 key[],
@ -188,7 +219,7 @@ Signed-off-by: Felix Fietkau <nbd@nbd.name>
#endif /* AES_CMAC_H */
--- a/net/mac80211/key.h
+++ b/net/mac80211/key.h
@@ -93,7 +93,7 @@ struct ieee80211_key {
@@ -94,7 +94,7 @@ struct ieee80211_key {
} ccmp;
struct {
u8 rx_pn[IEEE80211_CMAC_PN_LEN];

View File

@ -6,5 +6,5 @@
depends on CRYPTO_AES
- depends on CRYPTO_CMAC
depends on CRC32
---help---
help
This option enables the hardware independent IEEE 802.11

View File

@ -1,15 +0,0 @@
--- a/net/mac80211/tx.c
+++ b/net/mac80211/tx.c
@@ -4048,6 +4048,12 @@ out:
netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb,
struct net_device *dev)
{
+#if defined(sk_pacing_shift) || LINUX_VERSION_IS_GEQ(4,15,0)
+ if (skb->sk && sk_fullsock(skb->sk) &&
+ skb->sk->sk_pacing_shift != 6)
+ skb->sk->sk_pacing_shift = 6;
+#endif
+
if (unlikely(ieee80211_multicast_to_unicast(skb, dev))) {
struct sk_buff_head queue;

View File

@ -1,6 +1,6 @@
--- a/net/mac80211/main.c
+++ b/net/mac80211/main.c
@@ -314,7 +314,7 @@ void ieee80211_restart_hw(struct ieee802
@@ -321,7 +321,7 @@ void ieee80211_restart_hw(struct ieee802
}
EXPORT_SYMBOL(ieee80211_restart_hw);
@ -9,7 +9,7 @@
static int ieee80211_ifa_changed(struct notifier_block *nb,
unsigned long data, void *arg)
{
@@ -373,7 +373,7 @@ static int ieee80211_ifa_changed(struct
@@ -380,7 +380,7 @@ static int ieee80211_ifa_changed(struct
}
#endif
@ -18,7 +18,7 @@
static int ieee80211_ifa6_changed(struct notifier_block *nb,
unsigned long data, void *arg)
{
@@ -1267,14 +1267,14 @@ int ieee80211_register_hw(struct ieee802
@@ -1301,14 +1301,14 @@ int ieee80211_register_hw(struct ieee802
rtnl_unlock();
@ -35,7 +35,7 @@
local->ifa6_notifier.notifier_call = ieee80211_ifa6_changed;
result = register_inet6addr_notifier(&local->ifa6_notifier);
if (result)
@@ -1283,13 +1283,13 @@ int ieee80211_register_hw(struct ieee802
@@ -1317,13 +1317,13 @@ int ieee80211_register_hw(struct ieee802
return 0;
@ -52,7 +52,7 @@
fail_ifa:
#endif
wiphy_unregister(local->hw.wiphy);
@@ -1317,10 +1317,10 @@ void ieee80211_unregister_hw(struct ieee
@@ -1351,10 +1351,10 @@ void ieee80211_unregister_hw(struct ieee
tasklet_kill(&local->tx_pending_tasklet);
tasklet_kill(&local->tasklet);

View File

@ -1,6 +1,6 @@
--- a/net/mac80211/cfg.c
+++ b/net/mac80211/cfg.c
@@ -2318,7 +2318,7 @@ static int ieee80211_scan(struct wiphy *
@@ -2442,7 +2442,7 @@ static int ieee80211_scan(struct wiphy *
* the frames sent while scanning on other channel will be
* lost)
*/

View File

@ -1,201 +0,0 @@
From: Felix Fietkau <nbd@nbd.name>
Date: Sun, 17 Mar 2019 18:11:30 +0100
Subject: [PATCH] mac80211: optimize skb resizing
When forwarding unicast packets from ethernet to batman-adv over 802.11s
(with forwarding disabled), the typical required headroom to transmit
encrypted packets on mt76 is 32 (802.11) + 6 (802.11s) + 8 (CCMP) +
2 (padding) + 6 (LLC) + 18 (batman-adv) - 14 (old ethernet header) = 58 bytes.
On systems where NET_SKB_PAD is 64 this leads to a call to pskb_expand_head
for every packet, since mac80211 also tries to allocate 16 bytes status
headroom for radiotap headers.
This patch fixes these unnecessary reallocations by only requiring the extra
status headroom in ieee80211_tx_monitor()
If however a reallocation happens before that call, the status headroom gets
added there as well, in order to avoid double reallocation.
The patch also cleans up the code by moving the headroom calculation to
ieee80211_skb_resize.
Signed-off-by: Felix Fietkau <nbd@nbd.name>
---
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -1782,6 +1782,9 @@ int ieee80211_tx_control_port(struct wip
const u8 *dest, __be16 proto, bool unencrypted);
int ieee80211_probe_mesh_link(struct wiphy *wiphy, struct net_device *dev,
const u8 *buf, size_t len);
+int ieee80211_skb_resize(struct ieee80211_local *local,
+ struct ieee80211_sub_if_data *sdata,
+ struct sk_buff *skb, int hdrlen, int hdr_add);
/* HT */
void ieee80211_apply_htcap_overrides(struct ieee80211_sub_if_data *sdata,
--- a/net/mac80211/status.c
+++ b/net/mac80211/status.c
@@ -814,6 +814,11 @@ void ieee80211_tx_monitor(struct ieee802
struct net_device *prev_dev = NULL;
int rtap_len;
+ if (ieee80211_skb_resize(local, NULL, skb, 0, 0)) {
+ dev_kfree_skb(skb);
+ return;
+ }
+
/* send frame to monitor interfaces now */
rtap_len = ieee80211_tx_radiotap_len(info, status);
if (WARN_ON_ONCE(skb_headroom(skb) < rtap_len)) {
--- a/net/mac80211/tx.c
+++ b/net/mac80211/tx.c
@@ -1943,37 +1943,53 @@ static bool ieee80211_tx(struct ieee8021
}
/* device xmit handlers */
-
-static int ieee80211_skb_resize(struct ieee80211_sub_if_data *sdata,
- struct sk_buff *skb,
- int head_need, bool may_encrypt)
+int ieee80211_skb_resize(struct ieee80211_local *local,
+ struct ieee80211_sub_if_data *sdata,
+ struct sk_buff *skb, int hdr_len, int hdr_extra)
{
- struct ieee80211_local *local = sdata->local;
+ struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
struct ieee80211_hdr *hdr;
- bool enc_tailroom;
- int tail_need = 0;
-
- hdr = (struct ieee80211_hdr *) skb->data;
- enc_tailroom = may_encrypt &&
- (sdata->crypto_tx_tailroom_needed_cnt ||
- ieee80211_is_mgmt(hdr->frame_control));
-
- if (enc_tailroom) {
- tail_need = IEEE80211_ENCRYPT_TAILROOM;
- tail_need -= skb_tailroom(skb);
- tail_need = max_t(int, tail_need, 0);
+ int head_need, head_max;
+ int tail_need, tail_max;
+ bool enc_tailroom = false;
+
+ if (sdata && !hdr_len &&
+ !(info->flags & IEEE80211_TX_INTFL_DONT_ENCRYPT)) {
+ hdr = (struct ieee80211_hdr *) skb->data;
+ enc_tailroom = (sdata->crypto_tx_tailroom_needed_cnt ||
+ ieee80211_is_mgmt(hdr->frame_control));
+ hdr_len += sdata->encrypt_headroom;
+ }
+
+ head_need = head_max = hdr_len;
+ tail_need = tail_max = 0;
+ if (!sdata) {
+ head_need = head_max = local->tx_headroom;
+ } else {
+ head_max += hdr_extra;
+ head_max += max_t(int, local->tx_headroom,
+ local->hw.extra_tx_headroom);
+ head_need += local->hw.extra_tx_headroom;
+
+ tail_max = IEEE80211_ENCRYPT_TAILROOM;
+ if (enc_tailroom)
+ tail_need = tail_max;
}
if (skb_cloned(skb) &&
(!ieee80211_hw_check(&local->hw, SUPPORTS_CLONED_SKBS) ||
!skb_clone_writable(skb, ETH_HLEN) || enc_tailroom))
I802_DEBUG_INC(local->tx_expand_skb_head_cloned);
- else if (head_need || tail_need)
+ else if (head_need > skb_headroom(skb) ||
+ tail_need > skb_tailroom(skb))
I802_DEBUG_INC(local->tx_expand_skb_head);
else
return 0;
- if (pskb_expand_head(skb, head_need, tail_need, GFP_ATOMIC)) {
+ head_max = max_t(int, 0, head_max - skb_headroom(skb));
+ tail_max = max_t(int, 0, tail_max - skb_tailroom(skb));
+
+ if (pskb_expand_head(skb, head_max, tail_max, GFP_ATOMIC)) {
wiphy_debug(local->hw.wiphy,
"failed to reallocate TX buffer\n");
return -ENOMEM;
@@ -1989,18 +2005,8 @@ void ieee80211_xmit(struct ieee80211_sub
struct ieee80211_local *local = sdata->local;
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
struct ieee80211_hdr *hdr;
- int headroom;
- bool may_encrypt;
-
- may_encrypt = !(info->flags & IEEE80211_TX_INTFL_DONT_ENCRYPT);
- headroom = local->tx_headroom;
- if (may_encrypt)
- headroom += sdata->encrypt_headroom;
- headroom -= skb_headroom(skb);
- headroom = max_t(int, 0, headroom);
-
- if (ieee80211_skb_resize(sdata, skb, headroom, may_encrypt)) {
+ if (ieee80211_skb_resize(local, sdata, skb, 0, 0)) {
ieee80211_free_txskb(&local->hw, skb);
return;
}
@@ -2790,29 +2796,13 @@ static struct sk_buff *ieee80211_build_h
}
skb_pull(skb, skip_header_bytes);
- head_need = hdrlen + encaps_len + meshhdrlen - skb_headroom(skb);
+ head_need = hdrlen + encaps_len + meshhdrlen;
- /*
- * So we need to modify the skb header and hence need a copy of
- * that. The head_need variable above doesn't, so far, include
- * the needed header space that we don't need right away. If we
- * can, then we don't reallocate right now but only after the
- * frame arrives at the master device (if it does...)
- *
- * If we cannot, however, then we will reallocate to include all
- * the ever needed space. Also, if we need to reallocate it anyway,
- * make it big enough for everything we may ever need.
- */
-
- if (head_need > 0 || skb_cloned(skb)) {
- head_need += sdata->encrypt_headroom;
- head_need += local->tx_headroom;
- head_need = max_t(int, 0, head_need);
- if (ieee80211_skb_resize(sdata, skb, head_need, true)) {
- ieee80211_free_txskb(&local->hw, skb);
- skb = NULL;
- return ERR_PTR(-ENOMEM);
- }
+ if (ieee80211_skb_resize(local, sdata, skb, head_need,
+ sdata->encrypt_headroom)) {
+ ieee80211_free_txskb(&local->hw, skb);
+ skb = NULL;
+ return ERR_PTR(-ENOMEM);
}
if (encaps_data)
@@ -3427,7 +3417,6 @@ static bool ieee80211_xmit_fast(struct i
struct ieee80211_local *local = sdata->local;
u16 ethertype = (skb->data[12] << 8) | skb->data[13];
int extra_head = fast_tx->hdr_len - (ETH_HLEN - 2);
- int hw_headroom = sdata->local->hw.extra_tx_headroom;
struct ethhdr eth;
struct ieee80211_tx_info *info;
struct ieee80211_hdr *hdr = (void *)fast_tx->hdr;
@@ -3479,10 +3468,7 @@ static bool ieee80211_xmit_fast(struct i
* as the may-encrypt argument for the resize to not account for
* more room than we already have in 'extra_head'
*/
- if (unlikely(ieee80211_skb_resize(sdata, skb,
- max_t(int, extra_head + hw_headroom -
- skb_headroom(skb), 0),
- false))) {
+ if (unlikely(ieee80211_skb_resize(local, sdata, skb, extra_head, 0))) {
kfree_skb(skb);
return true;
}

View File

@ -1,61 +0,0 @@
From: Felix Fietkau <nbd@nbd.name>
Date: Sat, 28 Sep 2019 15:44:06 +0200
Subject: [PATCH] mac80211: minstrel: remove divisions in tx status path
Use a slightly different threshold for downgrading spatial streams to
make it easier to calculate without divisions.
Slightly reduces CPU overhead.
Signed-off-by: Felix Fietkau <nbd@nbd.name>
---
--- a/net/mac80211/rc80211_minstrel.c
+++ b/net/mac80211/rc80211_minstrel.c
@@ -289,8 +289,7 @@ minstrel_tx_status(void *priv, struct ie
if (mi->sample_deferred > 0)
mi->sample_deferred--;
- if (time_after(jiffies, mi->last_stats_update +
- (mp->update_interval * HZ) / 1000))
+ if (time_after(jiffies, mi->last_stats_update + mp->update_interval))
minstrel_update_stats(mp, mi);
}
--- a/net/mac80211/rc80211_minstrel_ht.c
+++ b/net/mac80211/rc80211_minstrel_ht.c
@@ -970,23 +970,21 @@ minstrel_ht_tx_status(void *priv, struct
*/
rate = minstrel_get_ratestats(mi, mi->max_tp_rate[0]);
if (rate->attempts > 30 &&
- MINSTREL_FRAC(rate->success, rate->attempts) <
- MINSTREL_FRAC(20, 100)) {
+ rate->success < rate->attempts / 4) {
minstrel_downgrade_rate(mi, &mi->max_tp_rate[0], true);
update = true;
}
rate2 = minstrel_get_ratestats(mi, mi->max_tp_rate[1]);
if (rate2->attempts > 30 &&
- MINSTREL_FRAC(rate2->success, rate2->attempts) <
- MINSTREL_FRAC(20, 100)) {
+ rate2->success < rate2->attempts / 4) {
minstrel_downgrade_rate(mi, &mi->max_tp_rate[1], false);
update = true;
}
}
if (time_after(jiffies, mi->last_stats_update +
- (mp->update_interval / 2 * HZ) / 1000)) {
+ mp->update_interval / 2)) {
update = true;
minstrel_ht_update_stats(mp, mi, true);
}
@@ -1666,7 +1664,7 @@ minstrel_ht_alloc(struct ieee80211_hw *h
mp->has_mrr = true;
mp->hw = hw;
- mp->update_interval = 100;
+ mp->update_interval = HZ / 10;
minstrel_ht_init_cck_rates(mp);

View File

@ -1,235 +0,0 @@
From: Felix Fietkau <nbd@nbd.name>
Date: Sat, 28 Sep 2019 15:46:06 +0200
Subject: [PATCH] mac80211: minstrel_ht: replace rate stats ewma with a
better moving average
Rate success probability usually fluctuates a lot under normal conditions.
With a simple EWMA, noise and fluctuation can be reduced by increasing the
window length, but that comes at the cost of introducing lag on sudden
changes.
This change replaces the EWMA implementation with a moving average that's
designed to significantly reduce lag while keeping a bigger window size
by being better at filtering out noise.
It is only slightly more expensive than the simple EWMA and still avoids
divisions in its calculation.
The algorithm is adapted from an implementation intended for a completely
different field (stock market trading), where the tradeoff of lag vs
noise filtering is equally important.
The algorithm works in the same way as the "smoothing filter" from
http://www.stockspotter.com/files/PredictiveIndicators.pdf adapted for
fixed-point math with some constants, using only addition, bit shifts
and multiplication
To better make use of the filtering and bigger window size, the update
interval is cut in half.
For testing, the algorithm can be reverted to the older one via debugfs
Signed-off-by: Felix Fietkau <nbd@nbd.name>
---
--- a/net/mac80211/rc80211_minstrel.c
+++ b/net/mac80211/rc80211_minstrel.c
@@ -157,14 +157,18 @@ minstrel_update_rates(struct minstrel_pr
* Recalculate statistics and counters of a given rate
*/
void
-minstrel_calc_rate_stats(struct minstrel_rate_stats *mrs)
+minstrel_calc_rate_stats(struct minstrel_priv *mp,
+ struct minstrel_rate_stats *mrs)
{
unsigned int cur_prob;
if (unlikely(mrs->attempts > 0)) {
mrs->sample_skipped = 0;
cur_prob = MINSTREL_FRAC(mrs->success, mrs->attempts);
- if (unlikely(!mrs->att_hist)) {
+ if (mp->new_avg) {
+ mrs->prob_ewma = minstrel_filter_avg_add(&mrs->avg,
+ cur_prob);
+ } else if (unlikely(!mrs->att_hist)) {
mrs->prob_ewma = cur_prob;
} else {
/*update exponential weighted moving avarage */
@@ -200,7 +204,7 @@ minstrel_update_stats(struct minstrel_pr
struct minstrel_rate_stats *tmp_mrs = &mi->r[tmp_prob_rate].stats;
/* Update statistics of success probability per rate */
- minstrel_calc_rate_stats(mrs);
+ minstrel_calc_rate_stats(mp, mrs);
/* Sample less often below the 10% chance of success.
* Sample less often above the 95% chance of success. */
@@ -289,7 +293,8 @@ minstrel_tx_status(void *priv, struct ie
if (mi->sample_deferred > 0)
mi->sample_deferred--;
- if (time_after(jiffies, mi->last_stats_update + mp->update_interval))
+ if (time_after(jiffies, mi->last_stats_update +
+ mp->update_interval / (mp->new_avg ? 2 : 1)))
minstrel_update_stats(mp, mi);
}
--- a/net/mac80211/rc80211_minstrel.h
+++ b/net/mac80211/rc80211_minstrel.h
@@ -19,6 +19,21 @@
#define MAX_THR_RATES 4
/*
+ * Coefficients for moving average with noise filter (period=16),
+ * scaled by 10 bits
+ *
+ * a1 = exp(-pi * sqrt(2) / period)
+ * coeff2 = 2 * a1 * cos(sqrt(2) * 2 * pi / period)
+ * coeff3 = -sqr(a1)
+ * coeff1 = 1 - coeff2 - coeff3
+ */
+#define MINSTREL_AVG_COEFF1 (MINSTREL_FRAC(1, 1) - \
+ MINSTREL_AVG_COEFF2 - \
+ MINSTREL_AVG_COEFF3)
+#define MINSTREL_AVG_COEFF2 0x00001499
+#define MINSTREL_AVG_COEFF3 -0x0000092e
+
+/*
* Perform EWMA (Exponentially Weighted Moving Average) calculation
*/
static inline int
@@ -32,6 +47,41 @@ minstrel_ewma(int old, int new, int weig
return old + incr;
}
+struct minstrel_avg_ctx {
+ s32 prev[2];
+};
+
+static inline int minstrel_filter_avg_add(struct minstrel_avg_ctx *ctx, s32 in)
+{
+ s32 out_1 = ctx->prev[0];
+ s32 out_2 = ctx->prev[1];
+ s32 val;
+
+ if (!in)
+ in += 1;
+
+ if (!out_1) {
+ val = out_1 = in;
+ goto out;
+ }
+
+ val = MINSTREL_AVG_COEFF1 * in;
+ val += MINSTREL_AVG_COEFF2 * out_1;
+ val += MINSTREL_AVG_COEFF3 * out_2;
+ val >>= MINSTREL_SCALE;
+
+ if (val > 1 << MINSTREL_SCALE)
+ val = 1 << MINSTREL_SCALE;
+ if (val < 0)
+ val = 1;
+
+out:
+ ctx->prev[1] = out_1;
+ ctx->prev[0] = val;
+
+ return val;
+}
+
struct minstrel_rate_stats {
/* current / last sampling period attempts/success counters */
u16 attempts, last_attempts;
@@ -40,6 +90,8 @@ struct minstrel_rate_stats {
/* total attempts/success counters */
u32 att_hist, succ_hist;
+ struct minstrel_avg_ctx avg;
+
/* prob_ewma - exponential weighted moving average of prob */
u16 prob_ewma;
@@ -95,6 +147,7 @@ struct minstrel_sta_info {
struct minstrel_priv {
struct ieee80211_hw *hw;
bool has_mrr;
+ bool new_avg;
u32 sample_switch;
unsigned int cw_min;
unsigned int cw_max;
@@ -126,7 +179,8 @@ extern const struct rate_control_ops mac
void minstrel_add_sta_debugfs(void *priv, void *priv_sta, struct dentry *dir);
/* Recalculate success probabilities and counters for a given rate using EWMA */
-void minstrel_calc_rate_stats(struct minstrel_rate_stats *mrs);
+void minstrel_calc_rate_stats(struct minstrel_priv *mp,
+ struct minstrel_rate_stats *mrs);
int minstrel_get_tp_avg(struct minstrel_rate *mr, int prob_ewma);
/* debugfs */
--- a/net/mac80211/rc80211_minstrel_ht.c
+++ b/net/mac80211/rc80211_minstrel_ht.c
@@ -737,7 +737,7 @@ minstrel_ht_update_stats(struct minstrel
mrs = &mg->rates[i];
mrs->retry_updated = false;
- minstrel_calc_rate_stats(mrs);
+ minstrel_calc_rate_stats(mp, mrs);
cur_prob = mrs->prob_ewma;
if (minstrel_ht_get_tp_avg(mi, group, i, cur_prob) == 0)
@@ -773,6 +773,8 @@ minstrel_ht_update_stats(struct minstrel
/* try to sample all available rates during each interval */
mi->sample_count *= 8;
+ if (mp->new_avg)
+ mi->sample_count /= 2;
if (sample)
minstrel_ht_rate_sample_switch(mp, mi);
@@ -889,6 +891,7 @@ minstrel_ht_tx_status(void *priv, struct
struct ieee80211_tx_rate *ar = info->status.rates;
struct minstrel_rate_stats *rate, *rate2, *rate_sample = NULL;
struct minstrel_priv *mp = priv;
+ u32 update_interval = mp->update_interval / 2;
bool last, update = false;
bool sample_status = false;
int i;
@@ -943,6 +946,10 @@ minstrel_ht_tx_status(void *priv, struct
switch (mi->sample_mode) {
case MINSTREL_SAMPLE_IDLE:
+ if (mp->new_avg &&
+ (mp->hw->max_rates > 1 ||
+ mi->total_packets_cur < SAMPLE_SWITCH_THR))
+ update_interval /= 2;
break;
case MINSTREL_SAMPLE_ACTIVE:
@@ -983,8 +990,7 @@ minstrel_ht_tx_status(void *priv, struct
}
}
- if (time_after(jiffies, mi->last_stats_update +
- mp->update_interval / 2)) {
+ if (time_after(jiffies, mi->last_stats_update + update_interval)) {
update = true;
minstrel_ht_update_stats(mp, mi, true);
}
@@ -1665,6 +1671,7 @@ minstrel_ht_alloc(struct ieee80211_hw *h
mp->hw = hw;
mp->update_interval = HZ / 10;
+ mp->new_avg = true;
minstrel_ht_init_cck_rates(mp);
@@ -1682,6 +1689,8 @@ static void minstrel_ht_add_debugfs(stru
&mp->fixed_rate_idx);
debugfs_create_u32("sample_switch", S_IRUGO | S_IWUSR, debugfsdir,
&mp->sample_switch);
+ debugfs_create_bool("new_avg", S_IRUGO | S_IWUSR, debugfsdir,
+ &mp->new_avg);
}
#endif

View File

@ -1,424 +0,0 @@
From: Felix Fietkau <nbd@nbd.name>
Date: Tue, 8 Oct 2019 18:54:46 +0200
Subject: [PATCH] mac80211: minstrel_ht: rename prob_ewma to prob_avg, use it
for the new average
Reduces per-rate data structure size
Signed-off-by: Felix Fietkau <nbd@nbd.name>
---
--- a/net/mac80211/rc80211_minstrel.c
+++ b/net/mac80211/rc80211_minstrel.c
@@ -70,7 +70,7 @@ rix_to_ndx(struct minstrel_sta_info *mi,
}
/* return current EMWA throughput */
-int minstrel_get_tp_avg(struct minstrel_rate *mr, int prob_ewma)
+int minstrel_get_tp_avg(struct minstrel_rate *mr, int prob_avg)
{
int usecs;
@@ -79,13 +79,13 @@ int minstrel_get_tp_avg(struct minstrel_
usecs = 1000000;
/* reset thr. below 10% success */
- if (mr->stats.prob_ewma < MINSTREL_FRAC(10, 100))
+ if (mr->stats.prob_avg < MINSTREL_FRAC(10, 100))
return 0;
- if (prob_ewma > MINSTREL_FRAC(90, 100))
+ if (prob_avg > MINSTREL_FRAC(90, 100))
return MINSTREL_TRUNC(100000 * (MINSTREL_FRAC(90, 100) / usecs));
else
- return MINSTREL_TRUNC(100000 * (prob_ewma / usecs));
+ return MINSTREL_TRUNC(100000 * (prob_avg / usecs));
}
/* find & sort topmost throughput rates */
@@ -98,8 +98,8 @@ minstrel_sort_best_tp_rates(struct minst
for (j = MAX_THR_RATES; j > 0; --j) {
tmp_mrs = &mi->r[tp_list[j - 1]].stats;
- if (minstrel_get_tp_avg(&mi->r[i], cur_mrs->prob_ewma) <=
- minstrel_get_tp_avg(&mi->r[tp_list[j - 1]], tmp_mrs->prob_ewma))
+ if (minstrel_get_tp_avg(&mi->r[i], cur_mrs->prob_avg) <=
+ minstrel_get_tp_avg(&mi->r[tp_list[j - 1]], tmp_mrs->prob_avg))
break;
}
@@ -166,15 +166,15 @@ minstrel_calc_rate_stats(struct minstrel
mrs->sample_skipped = 0;
cur_prob = MINSTREL_FRAC(mrs->success, mrs->attempts);
if (mp->new_avg) {
- mrs->prob_ewma = minstrel_filter_avg_add(&mrs->avg,
- cur_prob);
+ minstrel_filter_avg_add(&mrs->prob_avg,
+ &mrs->prob_avg_1, cur_prob);
} else if (unlikely(!mrs->att_hist)) {
- mrs->prob_ewma = cur_prob;
+ mrs->prob_avg = cur_prob;
} else {
/*update exponential weighted moving avarage */
- mrs->prob_ewma = minstrel_ewma(mrs->prob_ewma,
- cur_prob,
- EWMA_LEVEL);
+ mrs->prob_avg = minstrel_ewma(mrs->prob_avg,
+ cur_prob,
+ EWMA_LEVEL);
}
mrs->att_hist += mrs->attempts;
mrs->succ_hist += mrs->success;
@@ -208,8 +208,8 @@ minstrel_update_stats(struct minstrel_pr
/* Sample less often below the 10% chance of success.
* Sample less often above the 95% chance of success. */
- if (mrs->prob_ewma > MINSTREL_FRAC(95, 100) ||
- mrs->prob_ewma < MINSTREL_FRAC(10, 100)) {
+ if (mrs->prob_avg > MINSTREL_FRAC(95, 100) ||
+ mrs->prob_avg < MINSTREL_FRAC(10, 100)) {
mr->adjusted_retry_count = mrs->retry_count >> 1;
if (mr->adjusted_retry_count > 2)
mr->adjusted_retry_count = 2;
@@ -229,14 +229,14 @@ minstrel_update_stats(struct minstrel_pr
* choose the maximum throughput rate as max_prob_rate
* (2) if all success probabilities < 95%, the rate with
* highest success probability is chosen as max_prob_rate */
- if (mrs->prob_ewma >= MINSTREL_FRAC(95, 100)) {
- tmp_cur_tp = minstrel_get_tp_avg(mr, mrs->prob_ewma);
+ if (mrs->prob_avg >= MINSTREL_FRAC(95, 100)) {
+ tmp_cur_tp = minstrel_get_tp_avg(mr, mrs->prob_avg);
tmp_prob_tp = minstrel_get_tp_avg(&mi->r[tmp_prob_rate],
- tmp_mrs->prob_ewma);
+ tmp_mrs->prob_avg);
if (tmp_cur_tp >= tmp_prob_tp)
tmp_prob_rate = i;
} else {
- if (mrs->prob_ewma >= tmp_mrs->prob_ewma)
+ if (mrs->prob_avg >= tmp_mrs->prob_avg)
tmp_prob_rate = i;
}
}
@@ -426,7 +426,7 @@ minstrel_get_rate(void *priv, struct iee
* has a probability of >95%, we shouldn't be attempting
* to use it, as this only wastes precious airtime */
if (!mrr_capable &&
- (mi->r[ndx].stats.prob_ewma > MINSTREL_FRAC(95, 100)))
+ (mi->r[ndx].stats.prob_avg > MINSTREL_FRAC(95, 100)))
return;
mi->prev_sample = true;
@@ -577,7 +577,7 @@ static u32 minstrel_get_expected_through
* computing cur_tp
*/
tmp_mrs = &mi->r[idx].stats;
- tmp_cur_tp = minstrel_get_tp_avg(&mi->r[idx], tmp_mrs->prob_ewma) * 10;
+ tmp_cur_tp = minstrel_get_tp_avg(&mi->r[idx], tmp_mrs->prob_avg) * 10;
tmp_cur_tp = tmp_cur_tp * 1200 * 8 / 1024;
return tmp_cur_tp;
--- a/net/mac80211/rc80211_minstrel.h
+++ b/net/mac80211/rc80211_minstrel.h
@@ -47,14 +47,10 @@ minstrel_ewma(int old, int new, int weig
return old + incr;
}
-struct minstrel_avg_ctx {
- s32 prev[2];
-};
-
-static inline int minstrel_filter_avg_add(struct minstrel_avg_ctx *ctx, s32 in)
+static inline int minstrel_filter_avg_add(u16 *prev_1, u16 *prev_2, s32 in)
{
- s32 out_1 = ctx->prev[0];
- s32 out_2 = ctx->prev[1];
+ s32 out_1 = *prev_1;
+ s32 out_2 = *prev_2;
s32 val;
if (!in)
@@ -76,8 +72,8 @@ static inline int minstrel_filter_avg_ad
val = 1;
out:
- ctx->prev[1] = out_1;
- ctx->prev[0] = val;
+ *prev_2 = out_1;
+ *prev_1 = val;
return val;
}
@@ -90,10 +86,9 @@ struct minstrel_rate_stats {
/* total attempts/success counters */
u32 att_hist, succ_hist;
- struct minstrel_avg_ctx avg;
-
- /* prob_ewma - exponential weighted moving average of prob */
- u16 prob_ewma;
+ /* prob_avg - moving average of prob */
+ u16 prob_avg;
+ u16 prob_avg_1;
/* maximum retry counts */
u8 retry_count;
@@ -181,7 +176,7 @@ void minstrel_add_sta_debugfs(void *priv
/* Recalculate success probabilities and counters for a given rate using EWMA */
void minstrel_calc_rate_stats(struct minstrel_priv *mp,
struct minstrel_rate_stats *mrs);
-int minstrel_get_tp_avg(struct minstrel_rate *mr, int prob_ewma);
+int minstrel_get_tp_avg(struct minstrel_rate *mr, int prob_avg);
/* debugfs */
int minstrel_stats_open(struct inode *inode, struct file *file);
--- a/net/mac80211/rc80211_minstrel_debugfs.c
+++ b/net/mac80211/rc80211_minstrel_debugfs.c
@@ -90,8 +90,8 @@ minstrel_stats_open(struct inode *inode,
p += sprintf(p, "%6u ", mr->perfect_tx_time);
tp_max = minstrel_get_tp_avg(mr, MINSTREL_FRAC(100,100));
- tp_avg = minstrel_get_tp_avg(mr, mrs->prob_ewma);
- eprob = MINSTREL_TRUNC(mrs->prob_ewma * 1000);
+ tp_avg = minstrel_get_tp_avg(mr, mrs->prob_avg);
+ eprob = MINSTREL_TRUNC(mrs->prob_avg * 1000);
p += sprintf(p, "%4u.%1u %4u.%1u %3u.%1u"
" %3u %3u %-3u "
@@ -147,8 +147,8 @@ minstrel_stats_csv_open(struct inode *in
p += sprintf(p, "%u,",mr->perfect_tx_time);
tp_max = minstrel_get_tp_avg(mr, MINSTREL_FRAC(100,100));
- tp_avg = minstrel_get_tp_avg(mr, mrs->prob_ewma);
- eprob = MINSTREL_TRUNC(mrs->prob_ewma * 1000);
+ tp_avg = minstrel_get_tp_avg(mr, mrs->prob_avg);
+ eprob = MINSTREL_TRUNC(mrs->prob_avg * 1000);
p += sprintf(p, "%u.%u,%u.%u,%u.%u,%u,%u,%u,"
"%llu,%llu,%d,%d\n",
--- a/net/mac80211/rc80211_minstrel_ht.c
+++ b/net/mac80211/rc80211_minstrel_ht.c
@@ -346,12 +346,12 @@ minstrel_ht_avg_ampdu_len(struct minstre
*/
int
minstrel_ht_get_tp_avg(struct minstrel_ht_sta *mi, int group, int rate,
- int prob_ewma)
+ int prob_avg)
{
unsigned int nsecs = 0;
/* do not account throughput if sucess prob is below 10% */
- if (prob_ewma < MINSTREL_FRAC(10, 100))
+ if (prob_avg < MINSTREL_FRAC(10, 100))
return 0;
if (group != MINSTREL_CCK_GROUP)
@@ -365,11 +365,11 @@ minstrel_ht_get_tp_avg(struct minstrel_h
* account for collision related packet error rate fluctuation
* (prob is scaled - see MINSTREL_FRAC above)
*/
- if (prob_ewma > MINSTREL_FRAC(90, 100))
+ if (prob_avg > MINSTREL_FRAC(90, 100))
return MINSTREL_TRUNC(100000 * ((MINSTREL_FRAC(90, 100) * 1000)
/ nsecs));
else
- return MINSTREL_TRUNC(100000 * ((prob_ewma * 1000) / nsecs));
+ return MINSTREL_TRUNC(100000 * ((prob_avg * 1000) / nsecs));
}
/*
@@ -389,13 +389,13 @@ minstrel_ht_sort_best_tp_rates(struct mi
cur_group = index / MCS_GROUP_RATES;
cur_idx = index % MCS_GROUP_RATES;
- cur_prob = mi->groups[cur_group].rates[cur_idx].prob_ewma;
+ cur_prob = mi->groups[cur_group].rates[cur_idx].prob_avg;
cur_tp_avg = minstrel_ht_get_tp_avg(mi, cur_group, cur_idx, cur_prob);
do {
tmp_group = tp_list[j - 1] / MCS_GROUP_RATES;
tmp_idx = tp_list[j - 1] % MCS_GROUP_RATES;
- tmp_prob = mi->groups[tmp_group].rates[tmp_idx].prob_ewma;
+ tmp_prob = mi->groups[tmp_group].rates[tmp_idx].prob_avg;
tmp_tp_avg = minstrel_ht_get_tp_avg(mi, tmp_group, tmp_idx,
tmp_prob);
if (cur_tp_avg < tmp_tp_avg ||
@@ -432,7 +432,7 @@ minstrel_ht_set_best_prob_rate(struct mi
tmp_group = mi->max_prob_rate / MCS_GROUP_RATES;
tmp_idx = mi->max_prob_rate % MCS_GROUP_RATES;
- tmp_prob = mi->groups[tmp_group].rates[tmp_idx].prob_ewma;
+ tmp_prob = mi->groups[tmp_group].rates[tmp_idx].prob_avg;
tmp_tp_avg = minstrel_ht_get_tp_avg(mi, tmp_group, tmp_idx, tmp_prob);
/* if max_tp_rate[0] is from MCS_GROUP max_prob_rate get selected from
@@ -444,11 +444,11 @@ minstrel_ht_set_best_prob_rate(struct mi
max_gpr_group = mg->max_group_prob_rate / MCS_GROUP_RATES;
max_gpr_idx = mg->max_group_prob_rate % MCS_GROUP_RATES;
- max_gpr_prob = mi->groups[max_gpr_group].rates[max_gpr_idx].prob_ewma;
+ max_gpr_prob = mi->groups[max_gpr_group].rates[max_gpr_idx].prob_avg;
- if (mrs->prob_ewma > MINSTREL_FRAC(75, 100)) {
+ if (mrs->prob_avg > MINSTREL_FRAC(75, 100)) {
cur_tp_avg = minstrel_ht_get_tp_avg(mi, cur_group, cur_idx,
- mrs->prob_ewma);
+ mrs->prob_avg);
if (cur_tp_avg > tmp_tp_avg)
mi->max_prob_rate = index;
@@ -458,9 +458,9 @@ minstrel_ht_set_best_prob_rate(struct mi
if (cur_tp_avg > max_gpr_tp_avg)
mg->max_group_prob_rate = index;
} else {
- if (mrs->prob_ewma > tmp_prob)
+ if (mrs->prob_avg > tmp_prob)
mi->max_prob_rate = index;
- if (mrs->prob_ewma > max_gpr_prob)
+ if (mrs->prob_avg > max_gpr_prob)
mg->max_group_prob_rate = index;
}
}
@@ -482,12 +482,12 @@ minstrel_ht_assign_best_tp_rates(struct
tmp_group = tmp_cck_tp_rate[0] / MCS_GROUP_RATES;
tmp_idx = tmp_cck_tp_rate[0] % MCS_GROUP_RATES;
- tmp_prob = mi->groups[tmp_group].rates[tmp_idx].prob_ewma;
+ tmp_prob = mi->groups[tmp_group].rates[tmp_idx].prob_avg;
tmp_cck_tp = minstrel_ht_get_tp_avg(mi, tmp_group, tmp_idx, tmp_prob);
tmp_group = tmp_mcs_tp_rate[0] / MCS_GROUP_RATES;
tmp_idx = tmp_mcs_tp_rate[0] % MCS_GROUP_RATES;
- tmp_prob = mi->groups[tmp_group].rates[tmp_idx].prob_ewma;
+ tmp_prob = mi->groups[tmp_group].rates[tmp_idx].prob_avg;
tmp_mcs_tp = minstrel_ht_get_tp_avg(mi, tmp_group, tmp_idx, tmp_prob);
if (tmp_cck_tp_rate && tmp_cck_tp > tmp_mcs_tp) {
@@ -518,7 +518,7 @@ minstrel_ht_prob_rate_reduce_streams(str
continue;
tmp_idx = mg->max_group_prob_rate % MCS_GROUP_RATES;
- tmp_prob = mi->groups[group].rates[tmp_idx].prob_ewma;
+ tmp_prob = mi->groups[group].rates[tmp_idx].prob_avg;
if (tmp_tp < minstrel_ht_get_tp_avg(mi, group, tmp_idx, tmp_prob) &&
(minstrel_mcs_groups[group].streams < tmp_max_streams)) {
@@ -623,7 +623,7 @@ minstrel_ht_rate_sample_switch(struct mi
* If that fails, look again for a rate that is at least as fast
*/
mrs = minstrel_get_ratestats(mi, mi->max_tp_rate[0]);
- faster_rate = mrs->prob_ewma > MINSTREL_FRAC(75, 100);
+ faster_rate = mrs->prob_avg > MINSTREL_FRAC(75, 100);
minstrel_ht_find_probe_rates(mi, rates, &n_rates, faster_rate);
if (!n_rates && faster_rate)
minstrel_ht_find_probe_rates(mi, rates, &n_rates, false);
@@ -738,7 +738,7 @@ minstrel_ht_update_stats(struct minstrel
mrs = &mg->rates[i];
mrs->retry_updated = false;
minstrel_calc_rate_stats(mp, mrs);
- cur_prob = mrs->prob_ewma;
+ cur_prob = mrs->prob_avg;
if (minstrel_ht_get_tp_avg(mi, group, i, cur_prob) == 0)
continue;
@@ -1012,7 +1012,7 @@ minstrel_calc_retransmit(struct minstrel
unsigned int overhead = 0, overhead_rtscts = 0;
mrs = minstrel_get_ratestats(mi, index);
- if (mrs->prob_ewma < MINSTREL_FRAC(1, 10)) {
+ if (mrs->prob_avg < MINSTREL_FRAC(1, 10)) {
mrs->retry_count = 1;
mrs->retry_count_rtscts = 1;
return;
@@ -1069,7 +1069,7 @@ minstrel_ht_set_rate(struct minstrel_pri
if (!mrs->retry_updated)
minstrel_calc_retransmit(mp, mi, index);
- if (mrs->prob_ewma < MINSTREL_FRAC(20, 100) || !mrs->retry_count) {
+ if (mrs->prob_avg < MINSTREL_FRAC(20, 100) || !mrs->retry_count) {
ratetbl->rate[offset].count = 2;
ratetbl->rate[offset].count_rts = 2;
ratetbl->rate[offset].count_cts = 2;
@@ -1103,11 +1103,11 @@ minstrel_ht_set_rate(struct minstrel_pri
}
static inline int
-minstrel_ht_get_prob_ewma(struct minstrel_ht_sta *mi, int rate)
+minstrel_ht_get_prob_avg(struct minstrel_ht_sta *mi, int rate)
{
int group = rate / MCS_GROUP_RATES;
rate %= MCS_GROUP_RATES;
- return mi->groups[group].rates[rate].prob_ewma;
+ return mi->groups[group].rates[rate].prob_avg;
}
static int
@@ -1119,7 +1119,7 @@ minstrel_ht_get_max_amsdu_len(struct min
unsigned int duration;
/* Disable A-MSDU if max_prob_rate is bad */
- if (mi->groups[group].rates[rate].prob_ewma < MINSTREL_FRAC(50, 100))
+ if (mi->groups[group].rates[rate].prob_avg < MINSTREL_FRAC(50, 100))
return 1;
duration = g->duration[rate];
@@ -1142,7 +1142,7 @@ minstrel_ht_get_max_amsdu_len(struct min
* data packet size
*/
if (duration > MCS_DURATION(1, 0, 260) ||
- (minstrel_ht_get_prob_ewma(mi, mi->max_tp_rate[0]) <
+ (minstrel_ht_get_prob_avg(mi, mi->max_tp_rate[0]) <
MINSTREL_FRAC(75, 100)))
return 3200;
@@ -1247,7 +1247,7 @@ minstrel_get_sample_rate(struct minstrel
* rate, to avoid wasting airtime.
*/
sample_dur = minstrel_get_duration(sample_idx);
- if (mrs->prob_ewma > MINSTREL_FRAC(95, 100) ||
+ if (mrs->prob_avg > MINSTREL_FRAC(95, 100) ||
minstrel_get_duration(mi->max_prob_rate) * 3 < sample_dur)
return -1;
@@ -1711,7 +1711,7 @@ static u32 minstrel_ht_get_expected_thro
i = mi->max_tp_rate[0] / MCS_GROUP_RATES;
j = mi->max_tp_rate[0] % MCS_GROUP_RATES;
- prob = mi->groups[i].rates[j].prob_ewma;
+ prob = mi->groups[i].rates[j].prob_avg;
/* convert tp_avg from pkt per second in kbps */
tp_avg = minstrel_ht_get_tp_avg(mi, i, j, prob) * 10;
--- a/net/mac80211/rc80211_minstrel_ht.h
+++ b/net/mac80211/rc80211_minstrel_ht.h
@@ -119,6 +119,6 @@ struct minstrel_ht_sta_priv {
void minstrel_ht_add_sta_debugfs(void *priv, void *priv_sta, struct dentry *dir);
int minstrel_ht_get_tp_avg(struct minstrel_ht_sta *mi, int group, int rate,
- int prob_ewma);
+ int prob_avg);
#endif
--- a/net/mac80211/rc80211_minstrel_ht_debugfs.c
+++ b/net/mac80211/rc80211_minstrel_ht_debugfs.c
@@ -98,8 +98,8 @@ minstrel_ht_stats_dump(struct minstrel_h
p += sprintf(p, "%6u ", tx_time);
tp_max = minstrel_ht_get_tp_avg(mi, i, j, MINSTREL_FRAC(100, 100));
- tp_avg = minstrel_ht_get_tp_avg(mi, i, j, mrs->prob_ewma);
- eprob = MINSTREL_TRUNC(mrs->prob_ewma * 1000);
+ tp_avg = minstrel_ht_get_tp_avg(mi, i, j, mrs->prob_avg);
+ eprob = MINSTREL_TRUNC(mrs->prob_avg * 1000);
p += sprintf(p, "%4u.%1u %4u.%1u %3u.%1u"
" %3u %3u %-3u "
@@ -243,8 +243,8 @@ minstrel_ht_stats_csv_dump(struct minstr
p += sprintf(p, "%u,", tx_time);
tp_max = minstrel_ht_get_tp_avg(mi, i, j, MINSTREL_FRAC(100, 100));
- tp_avg = minstrel_ht_get_tp_avg(mi, i, j, mrs->prob_ewma);
- eprob = MINSTREL_TRUNC(mrs->prob_ewma * 1000);
+ tp_avg = minstrel_ht_get_tp_avg(mi, i, j, mrs->prob_avg);
+ eprob = MINSTREL_TRUNC(mrs->prob_avg * 1000);
p += sprintf(p, "%u.%u,%u.%u,%u.%u,%u,%u,"
"%u,%llu,%llu,",

View File

@ -28,7 +28,7 @@ Signed-off-by: Johannes Berg <johannes.berg@intel.com>
--- a/net/mac80211/sta_info.c
+++ b/net/mac80211/sta_info.c
@@ -325,6 +325,7 @@ struct sta_info *sta_info_alloc(struct i
@@ -357,6 +357,7 @@ struct sta_info *sta_info_alloc(struct i
INIT_WORK(&sta->drv_deliver_wk, sta_deliver_ps_frames);
INIT_WORK(&sta->ampdu_mlme.work, ieee80211_ba_session_work);
mutex_init(&sta->ampdu_mlme.mtx);

View File

@ -1,82 +0,0 @@
From: Markus Theil <markus.theil@tu-ilmenau.de>
Date: Wed, 18 Dec 2019 15:27:36 +0100
Subject: [PATCH] mac80211: fix tx status for no ack cases
Before this patch, frames which where successfully transmitted without
requiring acks where accounted as lost frames.
Signed-off-by: Markus Theil <markus.theil@tu-ilmenau.de>
Link: https://lore.kernel.org/r/20191218142736.15843-1-markus.theil@tu-ilmenau.de
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
---
--- a/net/mac80211/status.c
+++ b/net/mac80211/status.c
@@ -880,6 +880,7 @@ static void __ieee80211_tx_status(struct
int rates_idx;
bool send_to_cooked;
bool acked;
+ bool noack_success;
struct ieee80211_bar *bar;
int shift = 0;
int tid = IEEE80211_NUM_TIDS;
@@ -897,6 +898,8 @@ static void __ieee80211_tx_status(struct
clear_sta_flag(sta, WLAN_STA_SP);
acked = !!(info->flags & IEEE80211_TX_STAT_ACK);
+ noack_success = !!(info->flags &
+ IEEE80211_TX_STAT_NOACK_TRANSMITTED);
/* mesh Peer Service Period support */
if (ieee80211_vif_is_mesh(&sta->sdata->vif) &&
@@ -961,12 +964,12 @@ static void __ieee80211_tx_status(struct
ieee80211_handle_filtered_frame(local, sta, skb);
return;
} else {
- if (!acked)
+ if (!acked && !noack_success)
sta->status_stats.retry_failed++;
sta->status_stats.retry_count += retry_count;
if (ieee80211_is_data_present(fc)) {
- if (!acked)
+ if (!acked && !noack_success)
sta->status_stats.msdu_failed[tid]++;
sta->status_stats.msdu_retries[tid] +=
@@ -993,7 +996,7 @@ static void __ieee80211_tx_status(struct
info->status.tx_time, 0);
if (ieee80211_hw_check(&local->hw, REPORTS_TX_ACK_STATUS)) {
- if (info->flags & IEEE80211_TX_STAT_ACK) {
+ if (acked) {
if (sta->status_stats.lost_packets)
sta->status_stats.lost_packets = 0;
@@ -1001,6 +1004,8 @@ static void __ieee80211_tx_status(struct
if (test_sta_flag(sta, WLAN_STA_TDLS_PEER_AUTH))
sta->status_stats.last_tdls_pkt_time =
jiffies;
+ } else if (noack_success) {
+ /* nothing to do here, do not account as lost */
} else {
ieee80211_lost_packet(sta, info);
}
@@ -1127,7 +1132,7 @@ void ieee80211_tx_status_ext(struct ieee
sta = container_of(pubsta, struct sta_info, sta);
- if (!acked)
+ if (!acked && !noack_success)
sta->status_stats.retry_failed++;
sta->status_stats.retry_count += retry_count;
@@ -1142,6 +1147,8 @@ void ieee80211_tx_status_ext(struct ieee
sta->status_stats.last_tdls_pkt_time = jiffies;
} else if (test_sta_flag(sta, WLAN_STA_PS_STA)) {
return;
+ } else if (noack_success) {
+ /* nothing to do here, do not account as lost */
} else {
ieee80211_lost_packet(sta, info);
}

View File

@ -1,78 +0,0 @@
From: John Crispin <john@phrozen.org>
Date: Tue, 29 Oct 2019 10:13:02 +0100
Subject: [PATCH] mac80211: move store skb ack code to its own function
This patch moves the code handling SKBTX_WIFI_STATUS inside the TX path
into an extra function. This allows us to reuse it inside the 802.11 encap
offloading datapath.
Signed-off-by: John Crispin <john@phrozen.org>
Link: https://lore.kernel.org/r/20191029091304.7330-2-john@phrozen.org
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
---
--- a/net/mac80211/tx.c
+++ b/net/mac80211/tx.c
@@ -2445,6 +2445,33 @@ static int ieee80211_lookup_ra_sta(struc
return 0;
}
+static int ieee80211_store_ack_skb(struct ieee80211_local *local,
+ struct sk_buff *skb,
+ u32 *info_flags)
+{
+ struct sk_buff *ack_skb = skb_clone_sk(skb);
+ u16 info_id = 0;
+
+ if (ack_skb) {
+ unsigned long flags;
+ int id;
+
+ spin_lock_irqsave(&local->ack_status_lock, flags);
+ id = idr_alloc(&local->ack_status_frames, ack_skb,
+ 1, 0x10000, GFP_ATOMIC);
+ spin_unlock_irqrestore(&local->ack_status_lock, flags);
+
+ if (id >= 0) {
+ info_id = id;
+ *info_flags |= IEEE80211_TX_CTL_REQ_TX_STATUS;
+ } else {
+ kfree_skb(ack_skb);
+ }
+ }
+
+ return info_id;
+}
+
/**
* ieee80211_build_hdr - build 802.11 header in the given frame
* @sdata: virtual interface to build the header for
@@ -2738,26 +2765,8 @@ static struct sk_buff *ieee80211_build_h
}
if (unlikely(!multicast && skb->sk &&
- skb_shinfo(skb)->tx_flags & SKBTX_WIFI_STATUS)) {
- struct sk_buff *ack_skb = skb_clone_sk(skb);
-
- if (ack_skb) {
- unsigned long flags;
- int id;
-
- spin_lock_irqsave(&local->ack_status_lock, flags);
- id = idr_alloc(&local->ack_status_frames, ack_skb,
- 1, 0x10000, GFP_ATOMIC);
- spin_unlock_irqrestore(&local->ack_status_lock, flags);
-
- if (id >= 0) {
- info_id = id;
- info_flags |= IEEE80211_TX_CTL_REQ_TX_STATUS;
- } else {
- kfree_skb(ack_skb);
- }
- }
- }
+ skb_shinfo(skb)->tx_flags & SKBTX_WIFI_STATUS))
+ info_id = ieee80211_store_ack_skb(local, skb, &info_flags);
/*
* If the skb is shared we need to obtain our own copy.

View File

@ -1,67 +0,0 @@
From: =?UTF-8?q?Toke=20H=C3=B8iland-J=C3=B8rgensen?= <toke@redhat.com>
Date: Wed, 23 Oct 2019 11:59:00 +0200
Subject: [PATCH] mac80211: Shrink the size of ack_frame_id to make room for
tx_time_est
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
To implement airtime queue limiting, we need to keep a running account of
the estimated airtime of all skbs queued into the device. Do to this
correctly, we need to store the airtime estimate into the skb so we can
decrease the outstanding balance when the skb is freed. This means that the
time estimate must be stored somewhere that will survive for the lifetime
of the skb.
To get this, decrease the size of the ack_frame_id field to 6 bits, and
lower the size of the ID space accordingly. This leaves 10 bits for use for
tx_time_est, which is enough to store a maximum of 4096 us, if we shift the
values so they become units of 4us.
Signed-off-by: Toke Høiland-Jørgensen <toke@redhat.com>
Link: https://lore.kernel.org/r/157182474063.150713.16132669599100802716.stgit@toke.dk
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
---
--- a/include/net/mac80211.h
+++ b/include/net/mac80211.h
@@ -967,6 +967,7 @@ ieee80211_rate_get_vht_nss(const struct
* @band: the band to transmit on (use for checking for races)
* @hw_queue: HW queue to put the frame on, skb_get_queue_mapping() gives the AC
* @ack_frame_id: internal frame ID for TX status, used internally
+ * @tx_time_est: TX time estimate in units of 4us, used internally
* @control: union part for control data
* @control.rates: TX rates array to try
* @control.rts_cts_rate_idx: rate for RTS or CTS
@@ -1007,7 +1008,8 @@ struct ieee80211_tx_info {
u8 hw_queue;
- u16 ack_frame_id;
+ u16 ack_frame_id:6;
+ u16 tx_time_est:10;
union {
struct {
--- a/net/mac80211/cfg.c
+++ b/net/mac80211/cfg.c
@@ -3450,7 +3450,7 @@ int ieee80211_attach_ack_skb(struct ieee
spin_lock_irqsave(&local->ack_status_lock, spin_flags);
id = idr_alloc(&local->ack_status_frames, ack_skb,
- 1, 0x10000, GFP_ATOMIC);
+ 1, 0x40, GFP_ATOMIC);
spin_unlock_irqrestore(&local->ack_status_lock, spin_flags);
if (id < 0) {
--- a/net/mac80211/tx.c
+++ b/net/mac80211/tx.c
@@ -2458,7 +2458,7 @@ static int ieee80211_store_ack_skb(struc
spin_lock_irqsave(&local->ack_status_lock, flags);
id = idr_alloc(&local->ack_status_frames, ack_skb,
- 1, 0x10000, GFP_ATOMIC);
+ 1, 0x40, GFP_ATOMIC);
spin_unlock_irqrestore(&local->ack_status_lock, flags);
if (id >= 0) {

View File

@ -1,78 +0,0 @@
From: =?UTF-8?q?Toke=20H=C3=B8iland-J=C3=B8rgensen?= <toke@redhat.com>
Date: Tue, 12 Nov 2019 14:08:35 +0100
Subject: [PATCH] mac80211: Add new sta_info getter by sta/vif addrs
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
In ieee80211_tx_status() we don't have an sdata struct when looking up the
destination sta. Instead, we just do a lookup by the vif addr that is the
source of the packet being completed. Factor this out into a new sta_info
getter helper, since we need to use it for accounting AQL as well.
Signed-off-by: Toke Høiland-Jørgensen <toke@redhat.com>
Link: https://lore.kernel.org/r/20191112130835.382062-1-toke@redhat.com
[remove internal rcu_read_lock(), document instead]
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
---
--- a/net/mac80211/sta_info.c
+++ b/net/mac80211/sta_info.c
@@ -210,6 +210,20 @@ struct sta_info *sta_info_get_bss(struct
return NULL;
}
+struct sta_info *sta_info_get_by_addrs(struct ieee80211_local *local,
+ const u8 *sta_addr, const u8 *vif_addr)
+{
+ struct rhlist_head *tmp;
+ struct sta_info *sta;
+
+ for_each_sta_info(local, sta_addr, sta, tmp) {
+ if (ether_addr_equal(vif_addr, sta->sdata->vif.addr))
+ return sta;
+ }
+
+ return NULL;
+}
+
struct sta_info *sta_info_get_by_idx(struct ieee80211_sub_if_data *sdata,
int idx)
{
--- a/net/mac80211/sta_info.h
+++ b/net/mac80211/sta_info.h
@@ -726,6 +726,10 @@ struct sta_info *sta_info_get(struct iee
struct sta_info *sta_info_get_bss(struct ieee80211_sub_if_data *sdata,
const u8 *addr);
+/* user must hold sta_mtx or be in RCU critical section */
+struct sta_info *sta_info_get_by_addrs(struct ieee80211_local *local,
+ const u8 *sta_addr, const u8 *vif_addr);
+
#define for_each_sta_info(local, _addr, _sta, _tmp) \
rhl_for_each_entry_rcu(_sta, _tmp, \
sta_info_hash_lookup(local, _addr), hash_node)
--- a/net/mac80211/status.c
+++ b/net/mac80211/status.c
@@ -1085,19 +1085,13 @@ void ieee80211_tx_status(struct ieee8021
.skb = skb,
.info = IEEE80211_SKB_CB(skb),
};
- struct rhlist_head *tmp;
struct sta_info *sta;
rcu_read_lock();
- for_each_sta_info(local, hdr->addr1, sta, tmp) {
- /* skip wrong virtual interface */
- if (!ether_addr_equal(hdr->addr2, sta->sdata->vif.addr))
- continue;
-
+ sta = sta_info_get_by_addrs(local, hdr->addr1, hdr->addr2);
+ if (sta)
status.sta = &sta->sta;
- break;
- }
__ieee80211_tx_status(hw, &status);
rcu_read_unlock();

View File

@ -1,690 +0,0 @@
From: =?UTF-8?q?Toke=20H=C3=B8iland-J=C3=B8rgensen?= <toke@redhat.com>
Date: Mon, 18 Nov 2019 22:06:08 -0800
Subject: [PATCH] mac80211: Import airtime calculation code from mt76
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Felix recently added code to calculate airtime of packets to the mt76
driver. Import this into mac80211 so we can use it for airtime queue limit
calculations.
The airtime.c file is copied verbatim from the mt76 driver, and adjusted to
be usable in mac80211. This involves:
- Switching to mac80211 data structures.
- Adding support for 160 MHz channels and HE mode.
- Moving the symbol and duration calculations around a bit to avoid
rounding with the higher rates and longer symbol times used for HE rates.
The per-rate TX rate calculation is also split out to its own function so
it can be used directly for the AQL calculations later.
Signed-off-by: Toke Høiland-Jørgensen <toke@redhat.com>
Link: https://lore.kernel.org/r/20191119060610.76681-3-kyan@google.com
[fix HE_GROUP_IDX() to use 3 * bw, since there are 3 _gi values]
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
---
create mode 100644 net/mac80211/airtime.c
--- a/include/net/mac80211.h
+++ b/include/net/mac80211.h
@@ -6419,4 +6419,33 @@ void ieee80211_nan_func_match(struct iee
struct cfg80211_nan_match_params *match,
gfp_t gfp);
+/**
+ * ieee80211_calc_rx_airtime - calculate estimated transmission airtime for RX.
+ *
+ * This function calculates the estimated airtime usage of a frame based on the
+ * rate information in the RX status struct and the frame length.
+ *
+ * @hw: pointer as obtained from ieee80211_alloc_hw()
+ * @status: &struct ieee80211_rx_status containing the transmission rate
+ * information.
+ * @len: frame length in bytes
+ */
+u32 ieee80211_calc_rx_airtime(struct ieee80211_hw *hw,
+ struct ieee80211_rx_status *status,
+ int len);
+
+/**
+ * ieee80211_calc_tx_airtime - calculate estimated transmission airtime for TX.
+ *
+ * This function calculates the estimated airtime usage of a frame based on the
+ * rate information in the TX info struct and the frame length.
+ *
+ * @hw: pointer as obtained from ieee80211_alloc_hw()
+ * @info: &struct ieee80211_tx_info of the frame.
+ * @len: frame length in bytes
+ */
+u32 ieee80211_calc_tx_airtime(struct ieee80211_hw *hw,
+ struct ieee80211_tx_info *info,
+ int len);
+
#endif /* MAC80211_H */
--- a/net/mac80211/Makefile
+++ b/net/mac80211/Makefile
@@ -31,7 +31,8 @@ mac80211-y := \
chan.o \
trace.o mlme.o \
tdls.o \
- ocb.o
+ ocb.o \
+ airtime.o
mac80211-$(CPTCFG_MAC80211_LEDS) += led.o
mac80211-$(CPTCFG_MAC80211_DEBUGFS) += \
--- /dev/null
+++ b/net/mac80211/airtime.c
@@ -0,0 +1,597 @@
+// SPDX-License-Identifier: ISC
+/*
+ * Copyright (C) 2019 Felix Fietkau <nbd@nbd.name>
+ */
+
+#include <net/mac80211.h>
+#include "ieee80211_i.h"
+#include "sta_info.h"
+
+#define AVG_PKT_SIZE 1024
+
+/* Number of bits for an average sized packet */
+#define MCS_NBITS (AVG_PKT_SIZE << 3)
+
+/* Number of kilo-symbols (symbols * 1024) for a packet with (bps) bits per
+ * symbol. We use k-symbols to avoid rounding in the _TIME macros below.
+ */
+#define MCS_N_KSYMS(bps) DIV_ROUND_UP(MCS_NBITS << 10, (bps))
+
+/* Transmission time (in 1024 * usec) for a packet containing (ksyms) * 1024
+ * symbols.
+ */
+#define MCS_SYMBOL_TIME(sgi, ksyms) \
+ (sgi ? \
+ ((ksyms) * 4 * 18) / 20 : /* 3.6 us per sym */ \
+ ((ksyms) * 4) /* 4.0 us per sym */ \
+ )
+
+/* Transmit duration for the raw data part of an average sized packet */
+#define MCS_DURATION(streams, sgi, bps) \
+ ((u32)MCS_SYMBOL_TIME(sgi, MCS_N_KSYMS((streams) * (bps))))
+
+#define MCS_DURATION_S(shift, streams, sgi, bps) \
+ ((u16)((MCS_DURATION(streams, sgi, bps) >> shift)))
+
+/* These should match the values in enum nl80211_he_gi */
+#define HE_GI_08 0
+#define HE_GI_16 1
+#define HE_GI_32 2
+
+/* Transmission time (1024 usec) for a packet containing (ksyms) * k-symbols */
+#define HE_SYMBOL_TIME(gi, ksyms) \
+ (gi == HE_GI_08 ? \
+ ((ksyms) * 16 * 17) / 20 : /* 13.6 us per sym */ \
+ (gi == HE_GI_16 ? \
+ ((ksyms) * 16 * 18) / 20 : /* 14.4 us per sym */ \
+ ((ksyms) * 16) /* 16.0 us per sym */ \
+ ))
+
+/* Transmit duration for the raw data part of an average sized packet */
+#define HE_DURATION(streams, gi, bps) \
+ ((u32)HE_SYMBOL_TIME(gi, MCS_N_KSYMS((streams) * (bps))))
+
+#define HE_DURATION_S(shift, streams, gi, bps) \
+ (HE_DURATION(streams, gi, bps) >> shift)
+
+#define BW_20 0
+#define BW_40 1
+#define BW_80 2
+#define BW_160 3
+
+/*
+ * Define group sort order: HT40 -> SGI -> #streams
+ */
+#define IEEE80211_MAX_STREAMS 4
+#define IEEE80211_HT_STREAM_GROUPS 4 /* BW(=2) * SGI(=2) */
+#define IEEE80211_VHT_STREAM_GROUPS 8 /* BW(=4) * SGI(=2) */
+
+#define IEEE80211_HE_MAX_STREAMS 8
+#define IEEE80211_HE_STREAM_GROUPS 12 /* BW(=4) * GI(=3) */
+
+#define IEEE80211_HT_GROUPS_NB (IEEE80211_MAX_STREAMS * \
+ IEEE80211_HT_STREAM_GROUPS)
+#define IEEE80211_VHT_GROUPS_NB (IEEE80211_MAX_STREAMS * \
+ IEEE80211_VHT_STREAM_GROUPS)
+#define IEEE80211_HE_GROUPS_NB (IEEE80211_HE_MAX_STREAMS * \
+ IEEE80211_HE_STREAM_GROUPS)
+#define IEEE80211_GROUPS_NB (IEEE80211_HT_GROUPS_NB + \
+ IEEE80211_VHT_GROUPS_NB + \
+ IEEE80211_HE_GROUPS_NB)
+
+#define IEEE80211_HT_GROUP_0 0
+#define IEEE80211_VHT_GROUP_0 (IEEE80211_HT_GROUP_0 + IEEE80211_HT_GROUPS_NB)
+#define IEEE80211_HE_GROUP_0 (IEEE80211_VHT_GROUP_0 + IEEE80211_VHT_GROUPS_NB)
+
+#define MCS_GROUP_RATES 12
+
+#define HT_GROUP_IDX(_streams, _sgi, _ht40) \
+ IEEE80211_HT_GROUP_0 + \
+ IEEE80211_MAX_STREAMS * 2 * _ht40 + \
+ IEEE80211_MAX_STREAMS * _sgi + \
+ _streams - 1
+
+#define _MAX(a, b) (((a)>(b))?(a):(b))
+
+#define GROUP_SHIFT(duration) \
+ _MAX(0, 16 - __builtin_clz(duration))
+
+/* MCS rate information for an MCS group */
+#define __MCS_GROUP(_streams, _sgi, _ht40, _s) \
+ [HT_GROUP_IDX(_streams, _sgi, _ht40)] = { \
+ .shift = _s, \
+ .duration = { \
+ MCS_DURATION_S(_s, _streams, _sgi, _ht40 ? 54 : 26), \
+ MCS_DURATION_S(_s, _streams, _sgi, _ht40 ? 108 : 52), \
+ MCS_DURATION_S(_s, _streams, _sgi, _ht40 ? 162 : 78), \
+ MCS_DURATION_S(_s, _streams, _sgi, _ht40 ? 216 : 104), \
+ MCS_DURATION_S(_s, _streams, _sgi, _ht40 ? 324 : 156), \
+ MCS_DURATION_S(_s, _streams, _sgi, _ht40 ? 432 : 208), \
+ MCS_DURATION_S(_s, _streams, _sgi, _ht40 ? 486 : 234), \
+ MCS_DURATION_S(_s, _streams, _sgi, _ht40 ? 540 : 260) \
+ } \
+}
+
+#define MCS_GROUP_SHIFT(_streams, _sgi, _ht40) \
+ GROUP_SHIFT(MCS_DURATION(_streams, _sgi, _ht40 ? 54 : 26))
+
+#define MCS_GROUP(_streams, _sgi, _ht40) \
+ __MCS_GROUP(_streams, _sgi, _ht40, \
+ MCS_GROUP_SHIFT(_streams, _sgi, _ht40))
+
+#define VHT_GROUP_IDX(_streams, _sgi, _bw) \
+ (IEEE80211_VHT_GROUP_0 + \
+ IEEE80211_MAX_STREAMS * 2 * (_bw) + \
+ IEEE80211_MAX_STREAMS * (_sgi) + \
+ (_streams) - 1)
+
+#define BW2VBPS(_bw, r4, r3, r2, r1) \
+ (_bw == BW_160 ? r4 : _bw == BW_80 ? r3 : _bw == BW_40 ? r2 : r1)
+
+#define __VHT_GROUP(_streams, _sgi, _bw, _s) \
+ [VHT_GROUP_IDX(_streams, _sgi, _bw)] = { \
+ .shift = _s, \
+ .duration = { \
+ MCS_DURATION_S(_s, _streams, _sgi, \
+ BW2VBPS(_bw, 234, 117, 54, 26)), \
+ MCS_DURATION_S(_s, _streams, _sgi, \
+ BW2VBPS(_bw, 468, 234, 108, 52)), \
+ MCS_DURATION_S(_s, _streams, _sgi, \
+ BW2VBPS(_bw, 702, 351, 162, 78)), \
+ MCS_DURATION_S(_s, _streams, _sgi, \
+ BW2VBPS(_bw, 936, 468, 216, 104)), \
+ MCS_DURATION_S(_s, _streams, _sgi, \
+ BW2VBPS(_bw, 1404, 702, 324, 156)), \
+ MCS_DURATION_S(_s, _streams, _sgi, \
+ BW2VBPS(_bw, 1872, 936, 432, 208)), \
+ MCS_DURATION_S(_s, _streams, _sgi, \
+ BW2VBPS(_bw, 2106, 1053, 486, 234)), \
+ MCS_DURATION_S(_s, _streams, _sgi, \
+ BW2VBPS(_bw, 2340, 1170, 540, 260)), \
+ MCS_DURATION_S(_s, _streams, _sgi, \
+ BW2VBPS(_bw, 2808, 1404, 648, 312)), \
+ MCS_DURATION_S(_s, _streams, _sgi, \
+ BW2VBPS(_bw, 3120, 1560, 720, 346)) \
+ } \
+}
+
+#define VHT_GROUP_SHIFT(_streams, _sgi, _bw) \
+ GROUP_SHIFT(MCS_DURATION(_streams, _sgi, \
+ BW2VBPS(_bw, 243, 117, 54, 26)))
+
+#define VHT_GROUP(_streams, _sgi, _bw) \
+ __VHT_GROUP(_streams, _sgi, _bw, \
+ VHT_GROUP_SHIFT(_streams, _sgi, _bw))
+
+
+#define HE_GROUP_IDX(_streams, _gi, _bw) \
+ (IEEE80211_HE_GROUP_0 + \
+ IEEE80211_HE_MAX_STREAMS * 3 * (_bw) + \
+ IEEE80211_HE_MAX_STREAMS * (_gi) + \
+ (_streams) - 1)
+
+#define __HE_GROUP(_streams, _gi, _bw, _s) \
+ [HE_GROUP_IDX(_streams, _gi, _bw)] = { \
+ .shift = _s, \
+ .duration = { \
+ HE_DURATION_S(_s, _streams, _gi, \
+ BW2VBPS(_bw, 979, 489, 230, 115)), \
+ HE_DURATION_S(_s, _streams, _gi, \
+ BW2VBPS(_bw, 1958, 979, 475, 230)), \
+ HE_DURATION_S(_s, _streams, _gi, \
+ BW2VBPS(_bw, 2937, 1468, 705, 345)), \
+ HE_DURATION_S(_s, _streams, _gi, \
+ BW2VBPS(_bw, 3916, 1958, 936, 475)), \
+ HE_DURATION_S(_s, _streams, _gi, \
+ BW2VBPS(_bw, 5875, 2937, 1411, 705)), \
+ HE_DURATION_S(_s, _streams, _gi, \
+ BW2VBPS(_bw, 7833, 3916, 1872, 936)), \
+ HE_DURATION_S(_s, _streams, _gi, \
+ BW2VBPS(_bw, 8827, 4406, 2102, 1051)), \
+ HE_DURATION_S(_s, _streams, _gi, \
+ BW2VBPS(_bw, 9806, 4896, 2347, 1166)), \
+ HE_DURATION_S(_s, _streams, _gi, \
+ BW2VBPS(_bw, 11764, 5875, 2808, 1411)), \
+ HE_DURATION_S(_s, _streams, _gi, \
+ BW2VBPS(_bw, 13060, 6523, 3124, 1555)), \
+ HE_DURATION_S(_s, _streams, _gi, \
+ BW2VBPS(_bw, 14702, 7344, 3513, 1756)), \
+ HE_DURATION_S(_s, _streams, _gi, \
+ BW2VBPS(_bw, 16329, 8164, 3902, 1944)) \
+ } \
+}
+
+#define HE_GROUP_SHIFT(_streams, _gi, _bw) \
+ GROUP_SHIFT(HE_DURATION(_streams, _gi, \
+ BW2VBPS(_bw, 979, 489, 230, 115)))
+
+#define HE_GROUP(_streams, _gi, _bw) \
+ __HE_GROUP(_streams, _gi, _bw, \
+ HE_GROUP_SHIFT(_streams, _gi, _bw))
+struct mcs_group {
+ u8 shift;
+ u16 duration[MCS_GROUP_RATES];
+};
+
+static const struct mcs_group airtime_mcs_groups[] = {
+ MCS_GROUP(1, 0, BW_20),
+ MCS_GROUP(2, 0, BW_20),
+ MCS_GROUP(3, 0, BW_20),
+ MCS_GROUP(4, 0, BW_20),
+
+ MCS_GROUP(1, 1, BW_20),
+ MCS_GROUP(2, 1, BW_20),
+ MCS_GROUP(3, 1, BW_20),
+ MCS_GROUP(4, 1, BW_20),
+
+ MCS_GROUP(1, 0, BW_40),
+ MCS_GROUP(2, 0, BW_40),
+ MCS_GROUP(3, 0, BW_40),
+ MCS_GROUP(4, 0, BW_40),
+
+ MCS_GROUP(1, 1, BW_40),
+ MCS_GROUP(2, 1, BW_40),
+ MCS_GROUP(3, 1, BW_40),
+ MCS_GROUP(4, 1, BW_40),
+
+ VHT_GROUP(1, 0, BW_20),
+ VHT_GROUP(2, 0, BW_20),
+ VHT_GROUP(3, 0, BW_20),
+ VHT_GROUP(4, 0, BW_20),
+
+ VHT_GROUP(1, 1, BW_20),
+ VHT_GROUP(2, 1, BW_20),
+ VHT_GROUP(3, 1, BW_20),
+ VHT_GROUP(4, 1, BW_20),
+
+ VHT_GROUP(1, 0, BW_40),
+ VHT_GROUP(2, 0, BW_40),
+ VHT_GROUP(3, 0, BW_40),
+ VHT_GROUP(4, 0, BW_40),
+
+ VHT_GROUP(1, 1, BW_40),
+ VHT_GROUP(2, 1, BW_40),
+ VHT_GROUP(3, 1, BW_40),
+ VHT_GROUP(4, 1, BW_40),
+
+ VHT_GROUP(1, 0, BW_80),
+ VHT_GROUP(2, 0, BW_80),
+ VHT_GROUP(3, 0, BW_80),
+ VHT_GROUP(4, 0, BW_80),
+
+ VHT_GROUP(1, 1, BW_80),
+ VHT_GROUP(2, 1, BW_80),
+ VHT_GROUP(3, 1, BW_80),
+ VHT_GROUP(4, 1, BW_80),
+
+ VHT_GROUP(1, 0, BW_160),
+ VHT_GROUP(2, 0, BW_160),
+ VHT_GROUP(3, 0, BW_160),
+ VHT_GROUP(4, 0, BW_160),
+
+ VHT_GROUP(1, 1, BW_160),
+ VHT_GROUP(2, 1, BW_160),
+ VHT_GROUP(3, 1, BW_160),
+ VHT_GROUP(4, 1, BW_160),
+
+ HE_GROUP(1, HE_GI_08, BW_20),
+ HE_GROUP(2, HE_GI_08, BW_20),
+ HE_GROUP(3, HE_GI_08, BW_20),
+ HE_GROUP(4, HE_GI_08, BW_20),
+ HE_GROUP(5, HE_GI_08, BW_20),
+ HE_GROUP(6, HE_GI_08, BW_20),
+ HE_GROUP(7, HE_GI_08, BW_20),
+ HE_GROUP(8, HE_GI_08, BW_20),
+
+ HE_GROUP(1, HE_GI_16, BW_20),
+ HE_GROUP(2, HE_GI_16, BW_20),
+ HE_GROUP(3, HE_GI_16, BW_20),
+ HE_GROUP(4, HE_GI_16, BW_20),
+ HE_GROUP(5, HE_GI_16, BW_20),
+ HE_GROUP(6, HE_GI_16, BW_20),
+ HE_GROUP(7, HE_GI_16, BW_20),
+ HE_GROUP(8, HE_GI_16, BW_20),
+
+ HE_GROUP(1, HE_GI_32, BW_20),
+ HE_GROUP(2, HE_GI_32, BW_20),
+ HE_GROUP(3, HE_GI_32, BW_20),
+ HE_GROUP(4, HE_GI_32, BW_20),
+ HE_GROUP(5, HE_GI_32, BW_20),
+ HE_GROUP(6, HE_GI_32, BW_20),
+ HE_GROUP(7, HE_GI_32, BW_20),
+ HE_GROUP(8, HE_GI_32, BW_20),
+
+ HE_GROUP(1, HE_GI_08, BW_40),
+ HE_GROUP(2, HE_GI_08, BW_40),
+ HE_GROUP(3, HE_GI_08, BW_40),
+ HE_GROUP(4, HE_GI_08, BW_40),
+ HE_GROUP(5, HE_GI_08, BW_40),
+ HE_GROUP(6, HE_GI_08, BW_40),
+ HE_GROUP(7, HE_GI_08, BW_40),
+ HE_GROUP(8, HE_GI_08, BW_40),
+
+ HE_GROUP(1, HE_GI_16, BW_40),
+ HE_GROUP(2, HE_GI_16, BW_40),
+ HE_GROUP(3, HE_GI_16, BW_40),
+ HE_GROUP(4, HE_GI_16, BW_40),
+ HE_GROUP(5, HE_GI_16, BW_40),
+ HE_GROUP(6, HE_GI_16, BW_40),
+ HE_GROUP(7, HE_GI_16, BW_40),
+ HE_GROUP(8, HE_GI_16, BW_40),
+
+ HE_GROUP(1, HE_GI_32, BW_40),
+ HE_GROUP(2, HE_GI_32, BW_40),
+ HE_GROUP(3, HE_GI_32, BW_40),
+ HE_GROUP(4, HE_GI_32, BW_40),
+ HE_GROUP(5, HE_GI_32, BW_40),
+ HE_GROUP(6, HE_GI_32, BW_40),
+ HE_GROUP(7, HE_GI_32, BW_40),
+ HE_GROUP(8, HE_GI_32, BW_40),
+
+ HE_GROUP(1, HE_GI_08, BW_80),
+ HE_GROUP(2, HE_GI_08, BW_80),
+ HE_GROUP(3, HE_GI_08, BW_80),
+ HE_GROUP(4, HE_GI_08, BW_80),
+ HE_GROUP(5, HE_GI_08, BW_80),
+ HE_GROUP(6, HE_GI_08, BW_80),
+ HE_GROUP(7, HE_GI_08, BW_80),
+ HE_GROUP(8, HE_GI_08, BW_80),
+
+ HE_GROUP(1, HE_GI_16, BW_80),
+ HE_GROUP(2, HE_GI_16, BW_80),
+ HE_GROUP(3, HE_GI_16, BW_80),
+ HE_GROUP(4, HE_GI_16, BW_80),
+ HE_GROUP(5, HE_GI_16, BW_80),
+ HE_GROUP(6, HE_GI_16, BW_80),
+ HE_GROUP(7, HE_GI_16, BW_80),
+ HE_GROUP(8, HE_GI_16, BW_80),
+
+ HE_GROUP(1, HE_GI_32, BW_80),
+ HE_GROUP(2, HE_GI_32, BW_80),
+ HE_GROUP(3, HE_GI_32, BW_80),
+ HE_GROUP(4, HE_GI_32, BW_80),
+ HE_GROUP(5, HE_GI_32, BW_80),
+ HE_GROUP(6, HE_GI_32, BW_80),
+ HE_GROUP(7, HE_GI_32, BW_80),
+ HE_GROUP(8, HE_GI_32, BW_80),
+
+ HE_GROUP(1, HE_GI_08, BW_160),
+ HE_GROUP(2, HE_GI_08, BW_160),
+ HE_GROUP(3, HE_GI_08, BW_160),
+ HE_GROUP(4, HE_GI_08, BW_160),
+ HE_GROUP(5, HE_GI_08, BW_160),
+ HE_GROUP(6, HE_GI_08, BW_160),
+ HE_GROUP(7, HE_GI_08, BW_160),
+ HE_GROUP(8, HE_GI_08, BW_160),
+
+ HE_GROUP(1, HE_GI_16, BW_160),
+ HE_GROUP(2, HE_GI_16, BW_160),
+ HE_GROUP(3, HE_GI_16, BW_160),
+ HE_GROUP(4, HE_GI_16, BW_160),
+ HE_GROUP(5, HE_GI_16, BW_160),
+ HE_GROUP(6, HE_GI_16, BW_160),
+ HE_GROUP(7, HE_GI_16, BW_160),
+ HE_GROUP(8, HE_GI_16, BW_160),
+
+ HE_GROUP(1, HE_GI_32, BW_160),
+ HE_GROUP(2, HE_GI_32, BW_160),
+ HE_GROUP(3, HE_GI_32, BW_160),
+ HE_GROUP(4, HE_GI_32, BW_160),
+ HE_GROUP(5, HE_GI_32, BW_160),
+ HE_GROUP(6, HE_GI_32, BW_160),
+ HE_GROUP(7, HE_GI_32, BW_160),
+ HE_GROUP(8, HE_GI_32, BW_160),
+};
+
+static u32
+ieee80211_calc_legacy_rate_duration(u16 bitrate, bool short_pre,
+ bool cck, int len)
+{
+ u32 duration;
+
+ if (cck) {
+ duration = 144 + 48; /* preamble + PLCP */
+ if (short_pre)
+ duration >>= 1;
+
+ duration += 10; /* SIFS */
+ } else {
+ duration = 20 + 16; /* premable + SIFS */
+ }
+
+ len <<= 3;
+ duration += (len * 10) / bitrate;
+
+ return duration;
+}
+
+u32 ieee80211_calc_rx_airtime(struct ieee80211_hw *hw,
+ struct ieee80211_rx_status *status,
+ int len)
+{
+ struct ieee80211_supported_band *sband;
+ const struct ieee80211_rate *rate;
+ bool sgi = status->enc_flags & RX_ENC_FLAG_SHORT_GI;
+ bool sp = status->enc_flags & RX_ENC_FLAG_SHORTPRE;
+ int bw, streams;
+ int group, idx;
+ u32 duration;
+ bool cck;
+
+ switch (status->bw) {
+ case RATE_INFO_BW_20:
+ bw = BW_20;
+ break;
+ case RATE_INFO_BW_40:
+ bw = BW_40;
+ break;
+ case RATE_INFO_BW_80:
+ bw = BW_80;
+ break;
+ case RATE_INFO_BW_160:
+ bw = BW_160;
+ break;
+ default:
+ WARN_ON_ONCE(1);
+ return 0;
+ }
+
+ switch (status->encoding) {
+ case RX_ENC_LEGACY:
+ if (WARN_ON_ONCE(status->band > NL80211_BAND_5GHZ))
+ return 0;
+
+ sband = hw->wiphy->bands[status->band];
+ if (!sband || status->rate_idx > sband->n_bitrates)
+ return 0;
+
+ rate = &sband->bitrates[status->rate_idx];
+ cck = rate->flags & IEEE80211_RATE_MANDATORY_B;
+
+ return ieee80211_calc_legacy_rate_duration(rate->bitrate, sp,
+ cck, len);
+
+ case RX_ENC_VHT:
+ streams = status->nss;
+ idx = status->rate_idx;
+ group = VHT_GROUP_IDX(streams, sgi, bw);
+ break;
+ case RX_ENC_HT:
+ streams = ((status->rate_idx >> 3) & 3) + 1;
+ idx = status->rate_idx & 7;
+ group = HT_GROUP_IDX(streams, sgi, bw);
+ break;
+ case RX_ENC_HE:
+ streams = status->nss;
+ idx = status->rate_idx;
+ group = HE_GROUP_IDX(streams, status->he_gi, bw);
+ break;
+ default:
+ WARN_ON_ONCE(1);
+ return 0;
+ }
+
+ if (WARN_ON_ONCE((status->encoding != RX_ENC_HE && streams > 4) ||
+ (status->encoding == RX_ENC_HE && streams > 8)))
+ return 0;
+
+ duration = airtime_mcs_groups[group].duration[idx];
+ duration <<= airtime_mcs_groups[group].shift;
+ duration *= len;
+ duration /= AVG_PKT_SIZE;
+ duration /= 1024;
+
+ duration += 36 + (streams << 2);
+
+ return duration;
+}
+EXPORT_SYMBOL_GPL(ieee80211_calc_rx_airtime);
+
+static u32 ieee80211_calc_tx_airtime_rate(struct ieee80211_hw *hw,
+ struct ieee80211_tx_rate *rate,
+ u8 band, int len)
+{
+ struct ieee80211_rx_status stat = {
+ .band = band,
+ };
+
+ if (rate->idx < 0 || !rate->count)
+ return 0;
+
+ if (rate->flags & IEEE80211_TX_RC_80_MHZ_WIDTH)
+ stat.bw = RATE_INFO_BW_80;
+ else if (rate->flags & IEEE80211_TX_RC_40_MHZ_WIDTH)
+ stat.bw = RATE_INFO_BW_40;
+ else
+ stat.bw = RATE_INFO_BW_20;
+
+ stat.enc_flags = 0;
+ if (rate->flags & IEEE80211_TX_RC_USE_SHORT_PREAMBLE)
+ stat.enc_flags |= RX_ENC_FLAG_SHORTPRE;
+ if (rate->flags & IEEE80211_TX_RC_SHORT_GI)
+ stat.enc_flags |= RX_ENC_FLAG_SHORT_GI;
+
+ stat.rate_idx = rate->idx;
+ if (rate->flags & IEEE80211_TX_RC_VHT_MCS) {
+ stat.encoding = RX_ENC_VHT;
+ stat.rate_idx = ieee80211_rate_get_vht_mcs(rate);
+ stat.nss = ieee80211_rate_get_vht_nss(rate);
+ } else if (rate->flags & IEEE80211_TX_RC_MCS) {
+ stat.encoding = RX_ENC_HT;
+ } else {
+ stat.encoding = RX_ENC_LEGACY;
+ }
+
+ return ieee80211_calc_rx_airtime(hw, &stat, len);
+}
+
+u32 ieee80211_calc_tx_airtime(struct ieee80211_hw *hw,
+ struct ieee80211_tx_info *info,
+ int len)
+{
+ u32 duration = 0;
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(info->status.rates); i++) {
+ struct ieee80211_tx_rate *rate = &info->status.rates[i];
+ u32 cur_duration;
+
+ cur_duration = ieee80211_calc_tx_airtime_rate(hw, rate,
+ info->band, len);
+ if (!cur_duration)
+ break;
+
+ duration += cur_duration * rate->count;
+ }
+
+ return duration;
+}
+EXPORT_SYMBOL_GPL(ieee80211_calc_tx_airtime);
+
+u32 ieee80211_calc_expected_tx_airtime(struct ieee80211_hw *hw,
+ struct ieee80211_vif *vif,
+ struct ieee80211_sta *pubsta,
+ int len)
+{
+ struct ieee80211_supported_band *sband;
+ struct ieee80211_chanctx_conf *conf;
+ int rateidx, shift = 0;
+ bool cck, short_pream;
+ u32 basic_rates;
+ u8 band = 0;
+ u16 rate;
+
+ len += 38; /* Ethernet header length */
+
+ conf = rcu_dereference(vif->chanctx_conf);
+ if (conf) {
+ band = conf->def.chan->band;
+ shift = ieee80211_chandef_get_shift(&conf->def);
+ }
+
+ if (pubsta) {
+ struct sta_info *sta = container_of(pubsta, struct sta_info,
+ sta);
+
+ return ieee80211_calc_tx_airtime_rate(hw,
+ &sta->tx_stats.last_rate,
+ band, len);
+ }
+
+ if (!conf)
+ return 0;
+
+ /* No station to get latest rate from, so calculate the worst-case
+ * duration using the lowest configured basic rate.
+ */
+ sband = hw->wiphy->bands[band];
+
+ basic_rates = vif->bss_conf.basic_rates;
+ short_pream = vif->bss_conf.use_short_preamble;
+
+ rateidx = basic_rates ? ffs(basic_rates) - 1 : 0;
+ rate = sband->bitrates[rateidx].bitrate << shift;
+ cck = sband->bitrates[rateidx].flags & IEEE80211_RATE_MANDATORY_B;
+
+ return ieee80211_calc_legacy_rate_duration(rate, short_pream, cck, len);
+}
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -2253,6 +2253,10 @@ const char *ieee80211_get_reason_code_st
extern const struct ethtool_ops ieee80211_ethtool_ops;
+u32 ieee80211_calc_expected_tx_airtime(struct ieee80211_hw *hw,
+ struct ieee80211_vif *vif,
+ struct ieee80211_sta *pubsta,
+ int len);
#ifdef CPTCFG_MAC80211_NOINLINE
#define debug_noinline noinline
#else

View File

@ -1,446 +0,0 @@
From: Kan Yan <kyan@google.com>
Date: Mon, 18 Nov 2019 22:06:09 -0800
Subject: [PATCH] mac80211: Implement Airtime-based Queue Limit (AQL)
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
In order for the Fq_CoDel algorithm integrated in mac80211 layer to operate
effectively to control excessive queueing latency, the CoDel algorithm
requires an accurate measure of how long packets stays in the queue, AKA
sojourn time. The sojourn time measured at the mac80211 layer doesn't
include queueing latency in the lower layer (firmware/hardware) and CoDel
expects lower layer to have a short queue. However, most 802.11ac chipsets
offload tasks such TX aggregation to firmware or hardware, thus have a deep
lower layer queue.
Without a mechanism to control the lower layer queue size, packets only
stay in mac80211 layer transiently before being sent to firmware queue.
As a result, the sojourn time measured by CoDel in the mac80211 layer is
almost always lower than the CoDel latency target, hence CoDel does little
to control the latency, even when the lower layer queue causes excessive
latency.
The Byte Queue Limits (BQL) mechanism is commonly used to address the
similar issue with wired network interface. However, this method cannot be
applied directly to the wireless network interface. "Bytes" is not a
suitable measure of queue depth in the wireless network, as the data rate
can vary dramatically from station to station in the same network, from a
few Mbps to over Gbps.
This patch implements an Airtime-based Queue Limit (AQL) to make CoDel work
effectively with wireless drivers that utilized firmware/hardware
offloading. AQL allows each txq to release just enough packets to the lower
layer to form 1-2 large aggregations to keep hardware fully utilized and
retains the rest of the frames in mac80211 layer to be controlled by the
CoDel algorithm.
Signed-off-by: Kan Yan <kyan@google.com>
[ Toke: Keep API to set pending airtime internal, fix nits in commit msg ]
Signed-off-by: Toke Høiland-Jørgensen <toke@redhat.com>
Link: https://lore.kernel.org/r/20191119060610.76681-4-kyan@google.com
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
---
--- a/include/net/cfg80211.h
+++ b/include/net/cfg80211.h
@@ -2603,6 +2603,13 @@ enum wiphy_params_flags {
#define IEEE80211_DEFAULT_AIRTIME_WEIGHT 256
+/* The per TXQ device queue limit in airtime */
+#define IEEE80211_DEFAULT_AQL_TXQ_LIMIT_L 5000
+#define IEEE80211_DEFAULT_AQL_TXQ_LIMIT_H 12000
+
+/* The per interface airtime threshold to switch to lower queue limit */
+#define IEEE80211_AQL_THRESHOLD 24000
+
/**
* struct cfg80211_pmksa - PMK Security Association
*
--- a/include/net/mac80211.h
+++ b/include/net/mac80211.h
@@ -5559,6 +5559,18 @@ void ieee80211_sta_register_airtime(stru
u32 tx_airtime, u32 rx_airtime);
/**
+ * ieee80211_txq_airtime_check - check if a txq can send frame to device
+ *
+ * @hw: pointer obtained from ieee80211_alloc_hw()
+ * @txq: pointer obtained from station or virtual interface
+ *
+ * Return true if the AQL's airtime limit has not been reached and the txq can
+ * continue to send more packets to the device. Otherwise return false.
+ */
+bool
+ieee80211_txq_airtime_check(struct ieee80211_hw *hw, struct ieee80211_txq *txq);
+
+/**
* ieee80211_iter_keys - iterate keys programmed into the device
* @hw: pointer obtained from ieee80211_alloc_hw()
* @vif: virtual interface to iterate, may be %NULL for all
--- a/net/mac80211/debugfs.c
+++ b/net/mac80211/debugfs.c
@@ -148,6 +148,87 @@ static const struct file_operations aqm_
.llseek = default_llseek,
};
+static ssize_t aql_txq_limit_read(struct file *file,
+ char __user *user_buf,
+ size_t count,
+ loff_t *ppos)
+{
+ struct ieee80211_local *local = file->private_data;
+ char buf[400];
+ int len = 0;
+
+ len = scnprintf(buf, sizeof(buf),
+ "AC AQL limit low AQL limit high\n"
+ "VO %u %u\n"
+ "VI %u %u\n"
+ "BE %u %u\n"
+ "BK %u %u\n",
+ local->aql_txq_limit_low[IEEE80211_AC_VO],
+ local->aql_txq_limit_high[IEEE80211_AC_VO],
+ local->aql_txq_limit_low[IEEE80211_AC_VI],
+ local->aql_txq_limit_high[IEEE80211_AC_VI],
+ local->aql_txq_limit_low[IEEE80211_AC_BE],
+ local->aql_txq_limit_high[IEEE80211_AC_BE],
+ local->aql_txq_limit_low[IEEE80211_AC_BK],
+ local->aql_txq_limit_high[IEEE80211_AC_BK]);
+ return simple_read_from_buffer(user_buf, count, ppos,
+ buf, len);
+}
+
+static ssize_t aql_txq_limit_write(struct file *file,
+ const char __user *user_buf,
+ size_t count,
+ loff_t *ppos)
+{
+ struct ieee80211_local *local = file->private_data;
+ char buf[100];
+ size_t len;
+ u32 ac, q_limit_low, q_limit_high, q_limit_low_old, q_limit_high_old;
+ struct sta_info *sta;
+
+ if (count > sizeof(buf))
+ return -EINVAL;
+
+ if (copy_from_user(buf, user_buf, count))
+ return -EFAULT;
+
+ buf[sizeof(buf) - 1] = 0;
+ len = strlen(buf);
+ if (len > 0 && buf[len - 1] == '\n')
+ buf[len - 1] = 0;
+
+ if (sscanf(buf, "%u %u %u", &ac, &q_limit_low, &q_limit_high) != 3)
+ return -EINVAL;
+
+ if (ac >= IEEE80211_NUM_ACS)
+ return -EINVAL;
+
+ q_limit_low_old = local->aql_txq_limit_low[ac];
+ q_limit_high_old = local->aql_txq_limit_high[ac];
+
+ local->aql_txq_limit_low[ac] = q_limit_low;
+ local->aql_txq_limit_high[ac] = q_limit_high;
+
+ mutex_lock(&local->sta_mtx);
+ list_for_each_entry(sta, &local->sta_list, list) {
+ /* If a sta has customized queue limits, keep it */
+ if (sta->airtime[ac].aql_limit_low == q_limit_low_old &&
+ sta->airtime[ac].aql_limit_high == q_limit_high_old) {
+ sta->airtime[ac].aql_limit_low = q_limit_low;
+ sta->airtime[ac].aql_limit_high = q_limit_high;
+ }
+ }
+ mutex_unlock(&local->sta_mtx);
+ return count;
+}
+
+static const struct file_operations aql_txq_limit_ops = {
+ .write = aql_txq_limit_write,
+ .read = aql_txq_limit_read,
+ .open = simple_open,
+ .llseek = default_llseek,
+};
+
static ssize_t force_tx_status_read(struct file *file,
char __user *user_buf,
size_t count,
@@ -441,6 +522,10 @@ void debugfs_hw_add(struct ieee80211_loc
debugfs_create_u16("airtime_flags", 0600,
phyd, &local->airtime_flags);
+ DEBUGFS_ADD(aql_txq_limit);
+ debugfs_create_u32("aql_threshold", 0600,
+ phyd, &local->aql_threshold);
+
statsd = debugfs_create_dir("statistics", phyd);
/* if the dir failed, don't put all the other things into the root! */
--- a/net/mac80211/debugfs_sta.c
+++ b/net/mac80211/debugfs_sta.c
@@ -198,10 +198,12 @@ static ssize_t sta_airtime_read(struct f
{
struct sta_info *sta = file->private_data;
struct ieee80211_local *local = sta->sdata->local;
- size_t bufsz = 200;
+ size_t bufsz = 400;
char *buf = kzalloc(bufsz, GFP_KERNEL), *p = buf;
u64 rx_airtime = 0, tx_airtime = 0;
s64 deficit[IEEE80211_NUM_ACS];
+ u32 q_depth[IEEE80211_NUM_ACS];
+ u32 q_limit_l[IEEE80211_NUM_ACS], q_limit_h[IEEE80211_NUM_ACS];
ssize_t rv;
int ac;
@@ -213,19 +215,22 @@ static ssize_t sta_airtime_read(struct f
rx_airtime += sta->airtime[ac].rx_airtime;
tx_airtime += sta->airtime[ac].tx_airtime;
deficit[ac] = sta->airtime[ac].deficit;
+ q_limit_l[ac] = sta->airtime[ac].aql_limit_low;
+ q_limit_h[ac] = sta->airtime[ac].aql_limit_high;
spin_unlock_bh(&local->active_txq_lock[ac]);
+ q_depth[ac] = atomic_read(&sta->airtime[ac].aql_tx_pending);
}
p += scnprintf(p, bufsz + buf - p,
"RX: %llu us\nTX: %llu us\nWeight: %u\n"
- "Deficit: VO: %lld us VI: %lld us BE: %lld us BK: %lld us\n",
- rx_airtime,
- tx_airtime,
- sta->airtime_weight,
- deficit[0],
- deficit[1],
- deficit[2],
- deficit[3]);
+ "Deficit: VO: %lld us VI: %lld us BE: %lld us BK: %lld us\n"
+ "Q depth: VO: %u us VI: %u us BE: %u us BK: %u us\n"
+ "Q limit[low/high]: VO: %u/%u VI: %u/%u BE: %u/%u BK: %u/%u\n",
+ rx_airtime, tx_airtime, sta->airtime_weight,
+ deficit[0], deficit[1], deficit[2], deficit[3],
+ q_depth[0], q_depth[1], q_depth[2], q_depth[3],
+ q_limit_l[0], q_limit_h[0], q_limit_l[1], q_limit_h[1],
+ q_limit_l[2], q_limit_h[2], q_limit_l[3], q_limit_h[3]),
rv = simple_read_from_buffer(userbuf, count, ppos, buf, p - buf);
kfree(buf);
@@ -237,7 +242,25 @@ static ssize_t sta_airtime_write(struct
{
struct sta_info *sta = file->private_data;
struct ieee80211_local *local = sta->sdata->local;
- int ac;
+ u32 ac, q_limit_l, q_limit_h;
+ char _buf[100] = {}, *buf = _buf;
+
+ if (count > sizeof(_buf))
+ return -EINVAL;
+
+ if (copy_from_user(buf, userbuf, count))
+ return -EFAULT;
+
+ buf[sizeof(_buf) - 1] = '\0';
+ if (sscanf(buf, "queue limit %u %u %u", &ac, &q_limit_l, &q_limit_h)
+ != 3)
+ return -EINVAL;
+
+ if (ac >= IEEE80211_NUM_ACS)
+ return -EINVAL;
+
+ sta->airtime[ac].aql_limit_low = q_limit_l;
+ sta->airtime[ac].aql_limit_high = q_limit_h;
for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) {
spin_lock_bh(&local->active_txq_lock[ac]);
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -1142,6 +1142,10 @@ struct ieee80211_local {
u16 schedule_round[IEEE80211_NUM_ACS];
u16 airtime_flags;
+ u32 aql_txq_limit_low[IEEE80211_NUM_ACS];
+ u32 aql_txq_limit_high[IEEE80211_NUM_ACS];
+ u32 aql_threshold;
+ atomic_t aql_total_pending_airtime;
const struct ieee80211_ops *ops;
--- a/net/mac80211/main.c
+++ b/net/mac80211/main.c
@@ -669,8 +669,16 @@ struct ieee80211_hw *ieee80211_alloc_hw_
for (i = 0; i < IEEE80211_NUM_ACS; i++) {
INIT_LIST_HEAD(&local->active_txqs[i]);
spin_lock_init(&local->active_txq_lock[i]);
+ local->aql_txq_limit_low[i] = IEEE80211_DEFAULT_AQL_TXQ_LIMIT_L;
+ local->aql_txq_limit_high[i] =
+ IEEE80211_DEFAULT_AQL_TXQ_LIMIT_H;
}
- local->airtime_flags = AIRTIME_USE_TX | AIRTIME_USE_RX;
+
+ local->airtime_flags = AIRTIME_USE_TX |
+ AIRTIME_USE_RX |
+ AIRTIME_USE_AQL;
+ local->aql_threshold = IEEE80211_AQL_THRESHOLD;
+ atomic_set(&local->aql_total_pending_airtime, 0);
INIT_LIST_HEAD(&local->chanctx_list);
mutex_init(&local->chanctx_mtx);
--- a/net/mac80211/sta_info.c
+++ b/net/mac80211/sta_info.c
@@ -412,6 +412,9 @@ struct sta_info *sta_info_alloc(struct i
skb_queue_head_init(&sta->ps_tx_buf[i]);
skb_queue_head_init(&sta->tx_filtered[i]);
sta->airtime[i].deficit = sta->airtime_weight;
+ atomic_set(&sta->airtime[i].aql_tx_pending, 0);
+ sta->airtime[i].aql_limit_low = local->aql_txq_limit_low[i];
+ sta->airtime[i].aql_limit_high = local->aql_txq_limit_high[i];
}
for (i = 0; i < IEEE80211_NUM_TIDS; i++)
@@ -1914,6 +1917,41 @@ void ieee80211_sta_register_airtime(stru
}
EXPORT_SYMBOL(ieee80211_sta_register_airtime);
+void ieee80211_sta_update_pending_airtime(struct ieee80211_local *local,
+ struct sta_info *sta, u8 ac,
+ u16 tx_airtime, bool tx_completed)
+{
+ int tx_pending;
+
+ if (!tx_completed) {
+ if (sta)
+ atomic_add(tx_airtime,
+ &sta->airtime[ac].aql_tx_pending);
+
+ atomic_add(tx_airtime, &local->aql_total_pending_airtime);
+ return;
+ }
+
+ if (sta) {
+ tx_pending = atomic_sub_return(tx_airtime,
+ &sta->airtime[ac].aql_tx_pending);
+ if (WARN_ONCE(tx_pending < 0,
+ "STA %pM AC %d txq pending airtime underflow: %u, %u",
+ sta->addr, ac, tx_pending, tx_airtime))
+ atomic_cmpxchg(&sta->airtime[ac].aql_tx_pending,
+ tx_pending, 0);
+ }
+
+ tx_pending = atomic_sub_return(tx_airtime,
+ &local->aql_total_pending_airtime);
+ if (WARN_ONCE(tx_pending < 0,
+ "Device %s AC %d pending airtime underflow: %u, %u",
+ wiphy_name(local->hw.wiphy), ac, tx_pending,
+ tx_airtime))
+ atomic_cmpxchg(&local->aql_total_pending_airtime,
+ tx_pending, 0);
+}
+
int sta_info_move_state(struct sta_info *sta,
enum ieee80211_sta_state new_state)
{
--- a/net/mac80211/sta_info.h
+++ b/net/mac80211/sta_info.h
@@ -128,13 +128,21 @@ enum ieee80211_agg_stop_reason {
/* Debugfs flags to enable/disable use of RX/TX airtime in scheduler */
#define AIRTIME_USE_TX BIT(0)
#define AIRTIME_USE_RX BIT(1)
+#define AIRTIME_USE_AQL BIT(2)
struct airtime_info {
u64 rx_airtime;
u64 tx_airtime;
s64 deficit;
+ atomic_t aql_tx_pending; /* Estimated airtime for frames pending */
+ u32 aql_limit_low;
+ u32 aql_limit_high;
};
+void ieee80211_sta_update_pending_airtime(struct ieee80211_local *local,
+ struct sta_info *sta, u8 ac,
+ u16 tx_airtime, bool tx_completed);
+
struct sta_info;
/**
--- a/net/mac80211/tx.c
+++ b/net/mac80211/tx.c
@@ -3700,7 +3700,8 @@ struct ieee80211_txq *ieee80211_next_txq
{
struct ieee80211_local *local = hw_to_local(hw);
struct ieee80211_txq *ret = NULL;
- struct txq_info *txqi = NULL;
+ struct txq_info *txqi = NULL, *head = NULL;
+ bool found_eligible_txq = false;
spin_lock_bh(&local->active_txq_lock[ac]);
@@ -3711,13 +3712,30 @@ struct ieee80211_txq *ieee80211_next_txq
if (!txqi)
goto out;
+ if (txqi == head) {
+ if (!found_eligible_txq)
+ goto out;
+ else
+ found_eligible_txq = false;
+ }
+
+ if (!head)
+ head = txqi;
+
if (txqi->txq.sta) {
struct sta_info *sta = container_of(txqi->txq.sta,
- struct sta_info, sta);
+ struct sta_info, sta);
+ bool aql_check = ieee80211_txq_airtime_check(hw, &txqi->txq);
+ s64 deficit = sta->airtime[txqi->txq.ac].deficit;
- if (sta->airtime[txqi->txq.ac].deficit < 0) {
+ if (aql_check)
+ found_eligible_txq = true;
+
+ if (deficit < 0)
sta->airtime[txqi->txq.ac].deficit +=
sta->airtime_weight;
+
+ if (deficit < 0 || !aql_check) {
list_move_tail(&txqi->schedule_order,
&local->active_txqs[txqi->txq.ac]);
goto begin;
@@ -3771,6 +3789,33 @@ void __ieee80211_schedule_txq(struct iee
}
EXPORT_SYMBOL(__ieee80211_schedule_txq);
+bool ieee80211_txq_airtime_check(struct ieee80211_hw *hw,
+ struct ieee80211_txq *txq)
+{
+ struct sta_info *sta;
+ struct ieee80211_local *local = hw_to_local(hw);
+
+ if (!(local->airtime_flags & AIRTIME_USE_AQL))
+ return true;
+
+ if (!txq->sta)
+ return true;
+
+ sta = container_of(txq->sta, struct sta_info, sta);
+ if (atomic_read(&sta->airtime[txq->ac].aql_tx_pending) <
+ sta->airtime[txq->ac].aql_limit_low)
+ return true;
+
+ if (atomic_read(&local->aql_total_pending_airtime) <
+ local->aql_threshold &&
+ atomic_read(&sta->airtime[txq->ac].aql_tx_pending) <
+ sta->airtime[txq->ac].aql_limit_high)
+ return true;
+
+ return false;
+}
+EXPORT_SYMBOL(ieee80211_txq_airtime_check);
+
bool ieee80211_txq_may_transmit(struct ieee80211_hw *hw,
struct ieee80211_txq *txq)
{

View File

@ -0,0 +1,95 @@
From: Felix Fietkau <nbd@nbd.name>
Date: Wed, 25 Nov 2020 18:03:46 +0100
Subject: [PATCH] net/fq_impl: bulk-free packets from a flow on overmemory
This is similar to what sch_fq_codel does. It also amortizes the worst
case cost of a follow-up patch that changes the selection of the biggest
flow for dropping packets
Signed-off-by: Felix Fietkau <nbd@nbd.name>
---
--- a/include/net/fq_impl.h
+++ b/include/net/fq_impl.h
@@ -11,17 +11,25 @@
/* functions that are embedded into includer */
+
+static void
+__fq_adjust_removal(struct fq *fq, struct fq_flow *flow, unsigned int packets,
+ unsigned int bytes, unsigned int truesize)
+{
+ struct fq_tin *tin = flow->tin;
+
+ tin->backlog_bytes -= bytes;
+ tin->backlog_packets -= packets;
+ flow->backlog -= bytes;
+ fq->backlog -= packets;
+ fq->memory_usage -= truesize;
+}
+
static void fq_adjust_removal(struct fq *fq,
struct fq_flow *flow,
struct sk_buff *skb)
{
- struct fq_tin *tin = flow->tin;
-
- tin->backlog_bytes -= skb->len;
- tin->backlog_packets--;
- flow->backlog -= skb->len;
- fq->backlog--;
- fq->memory_usage -= skb->truesize;
+ __fq_adjust_removal(fq, flow, 1, skb->len, skb->truesize);
}
static void fq_rejigger_backlog(struct fq *fq, struct fq_flow *flow)
@@ -59,6 +67,34 @@ static struct sk_buff *fq_flow_dequeue(s
return skb;
}
+static int fq_flow_drop(struct fq *fq, struct fq_flow *flow,
+ fq_skb_free_t free_func)
+{
+ unsigned int packets = 0, bytes = 0, truesize = 0;
+ struct fq_tin *tin = flow->tin;
+ struct sk_buff *skb;
+ int pending;
+
+ lockdep_assert_held(&fq->lock);
+
+ pending = min_t(int, 32, skb_queue_len(&flow->queue) / 2);
+ do {
+ skb = __skb_dequeue(&flow->queue);
+ if (!skb)
+ break;
+
+ packets++;
+ bytes += skb->len;
+ truesize += skb->truesize;
+ free_func(fq, tin, flow, skb);
+ } while (packets < pending);
+
+ __fq_adjust_removal(fq, flow, packets, bytes, truesize);
+ fq_rejigger_backlog(fq, flow);
+
+ return packets;
+}
+
static struct sk_buff *fq_tin_dequeue(struct fq *fq,
struct fq_tin *tin,
fq_tin_dequeue_t dequeue_func)
@@ -190,12 +226,9 @@ static void fq_tin_enqueue(struct fq *fq
if (!flow)
return;
- skb = fq_flow_dequeue(fq, flow);
- if (!skb)
+ if (!fq_flow_drop(fq, flow, free_func))
return;
- free_func(fq, flow->tin, flow, skb);
-
flow->tin->overlimit++;
fq->overlimit++;
if (oom) {

View File

@ -1,146 +0,0 @@
From: =?UTF-8?q?Toke=20H=C3=B8iland-J=C3=B8rgensen?= <toke@redhat.com>
Date: Mon, 18 Nov 2019 22:06:10 -0800
Subject: [PATCH] mac80211: Use Airtime-based Queue Limits (AQL) on packet
dequeue
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
The previous commit added the ability to throttle stations when they queue
too much airtime in the hardware. This commit enables the functionality by
calculating the expected airtime usage of each packet that is dequeued from
the TXQs in mac80211, and accounting that as pending airtime.
The estimated airtime for each skb is stored in the tx_info, so we can
subtract the same amount from the running total when the skb is freed or
recycled. The throttling mechanism relies on this accounting to be
accurate (i.e., that we are not freeing skbs without subtracting any
airtime they were accounted for), so we put the subtraction into
ieee80211_report_used_skb(). As an optimisation, we also subtract the
airtime on regular TX completion, zeroing out the value stored in the
packet afterwards, to avoid having to do an expensive lookup of the station
from the packet data on every packet.
This patch does *not* include any mechanism to wake a throttled TXQ again,
on the assumption that this will happen anyway as a side effect of whatever
freed the skb (most commonly a TX completion).
Signed-off-by: Toke Høiland-Jørgensen <toke@redhat.com>
Link: https://lore.kernel.org/r/20191119060610.76681-5-kyan@google.com
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
---
--- a/include/net/mac80211.h
+++ b/include/net/mac80211.h
@@ -1060,6 +1060,22 @@ struct ieee80211_tx_info {
};
};
+static inline u16
+ieee80211_info_set_tx_time_est(struct ieee80211_tx_info *info, u16 tx_time_est)
+{
+ /* We only have 10 bits in tx_time_est, so store airtime
+ * in increments of 4us and clamp the maximum to 2**12-1
+ */
+ info->tx_time_est = min_t(u16, tx_time_est, 4095) >> 2;
+ return info->tx_time_est << 2;
+}
+
+static inline u16
+ieee80211_info_get_tx_time_est(struct ieee80211_tx_info *info)
+{
+ return info->tx_time_est << 2;
+}
+
/**
* struct ieee80211_tx_status - extended tx staus info for rate control
*
--- a/net/mac80211/status.c
+++ b/net/mac80211/status.c
@@ -669,12 +669,26 @@ static void ieee80211_report_used_skb(st
struct sk_buff *skb, bool dropped)
{
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
+ u16 tx_time_est = ieee80211_info_get_tx_time_est(info);
struct ieee80211_hdr *hdr = (void *)skb->data;
bool acked = info->flags & IEEE80211_TX_STAT_ACK;
if (dropped)
acked = false;
+ if (tx_time_est) {
+ struct sta_info *sta;
+
+ rcu_read_lock();
+
+ sta = sta_info_get_by_addrs(local, hdr->addr1, hdr->addr2);
+ ieee80211_sta_update_pending_airtime(local, sta,
+ skb_get_queue_mapping(skb),
+ tx_time_est,
+ true);
+ rcu_read_unlock();
+ }
+
if (info->flags & IEEE80211_TX_INTFL_MLME_CONN_TX) {
struct ieee80211_sub_if_data *sdata;
@@ -884,6 +898,7 @@ static void __ieee80211_tx_status(struct
struct ieee80211_bar *bar;
int shift = 0;
int tid = IEEE80211_NUM_TIDS;
+ u16 tx_time_est;
rates_idx = ieee80211_tx_get_rates(hw, info, &retry_count);
@@ -995,6 +1010,17 @@ static void __ieee80211_tx_status(struct
ieee80211_sta_register_airtime(&sta->sta, tid,
info->status.tx_time, 0);
+ if ((tx_time_est = ieee80211_info_get_tx_time_est(info)) > 0) {
+ /* Do this here to avoid the expensive lookup of the sta
+ * in ieee80211_report_used_skb().
+ */
+ ieee80211_sta_update_pending_airtime(local, sta,
+ skb_get_queue_mapping(skb),
+ tx_time_est,
+ true);
+ ieee80211_info_set_tx_time_est(info, 0);
+ }
+
if (ieee80211_hw_check(&local->hw, REPORTS_TX_ACK_STATUS)) {
if (acked) {
if (sta->status_stats.lost_packets)
--- a/net/mac80211/tx.c
+++ b/net/mac80211/tx.c
@@ -3559,6 +3559,9 @@ struct sk_buff *ieee80211_tx_dequeue(str
WARN_ON_ONCE(softirq_count() == 0);
+ if (!ieee80211_txq_airtime_check(hw, txq))
+ return NULL;
+
begin:
spin_lock_bh(&fq->lock);
@@ -3687,6 +3690,21 @@ begin:
}
IEEE80211_SKB_CB(skb)->control.vif = vif;
+
+ if (local->airtime_flags & AIRTIME_USE_AQL) {
+ u32 airtime;
+
+ airtime = ieee80211_calc_expected_tx_airtime(hw, vif, txq->sta,
+ skb->len);
+ if (airtime) {
+ airtime = ieee80211_info_set_tx_time_est(info, airtime);
+ ieee80211_sta_update_pending_airtime(local, tx.sta,
+ txq->ac,
+ airtime,
+ false);
+ }
+ }
+
return skb;
out:

View File

@ -0,0 +1,144 @@
From: Felix Fietkau <nbd@nbd.name>
Date: Wed, 25 Nov 2020 18:09:10 +0100
Subject: [PATCH] net/fq_impl: drop get_default_func, move default flow to
fq_tin
Simplifies the code and prepares for a rework of scanning for flows on
overmemory drop.
Signed-off-by: Felix Fietkau <nbd@nbd.name>
---
--- a/include/net/fq.h
+++ b/include/net/fq.h
@@ -47,6 +47,7 @@ struct fq_flow {
struct fq_tin {
struct list_head new_flows;
struct list_head old_flows;
+ struct fq_flow default_flow;
u32 backlog_bytes;
u32 backlog_packets;
u32 overlimit;
--- a/include/net/fq_impl.h
+++ b/include/net/fq_impl.h
@@ -151,8 +151,7 @@ static u32 fq_flow_idx(struct fq *fq, st
static struct fq_flow *fq_flow_classify(struct fq *fq,
struct fq_tin *tin, u32 idx,
- struct sk_buff *skb,
- fq_flow_get_default_t get_default_func)
+ struct sk_buff *skb)
{
struct fq_flow *flow;
@@ -160,7 +159,7 @@ static struct fq_flow *fq_flow_classify(
flow = &fq->flows[idx];
if (flow->tin && flow->tin != tin) {
- flow = get_default_func(fq, tin, idx, skb);
+ flow = &tin->default_flow;
tin->collisions++;
fq->collisions++;
}
@@ -192,15 +191,14 @@ static void fq_recalc_backlog(struct fq
static void fq_tin_enqueue(struct fq *fq,
struct fq_tin *tin, u32 idx,
struct sk_buff *skb,
- fq_skb_free_t free_func,
- fq_flow_get_default_t get_default_func)
+ fq_skb_free_t free_func)
{
struct fq_flow *flow;
bool oom;
lockdep_assert_held(&fq->lock);
- flow = fq_flow_classify(fq, tin, idx, skb, get_default_func);
+ flow = fq_flow_classify(fq, tin, idx, skb);
flow->tin = tin;
flow->backlog += skb->len;
@@ -331,6 +329,7 @@ static void fq_tin_init(struct fq_tin *t
{
INIT_LIST_HEAD(&tin->new_flows);
INIT_LIST_HEAD(&tin->old_flows);
+ fq_flow_init(&tin->default_flow);
}
static int fq_init(struct fq *fq, int flows_cnt)
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -855,7 +855,6 @@ enum txq_info_flags {
*/
struct txq_info {
struct fq_tin tin;
- struct fq_flow def_flow;
struct codel_vars def_cvars;
struct codel_stats cstats;
struct sk_buff_head frags;
--- a/net/mac80211/tx.c
+++ b/net/mac80211/tx.c
@@ -1322,7 +1322,7 @@ static struct sk_buff *codel_dequeue_fun
fq = &local->fq;
if (cvars == &txqi->def_cvars)
- flow = &txqi->def_flow;
+ flow = &txqi->tin.default_flow;
else
flow = &fq->flows[cvars - local->cvars];
@@ -1365,7 +1365,7 @@ static struct sk_buff *fq_tin_dequeue_fu
cparams = &local->cparams;
}
- if (flow == &txqi->def_flow)
+ if (flow == &tin->default_flow)
cvars = &txqi->def_cvars;
else
cvars = &local->cvars[flow - fq->flows];
@@ -1392,17 +1392,6 @@ static void fq_skb_free_func(struct fq *
ieee80211_free_txskb(&local->hw, skb);
}
-static struct fq_flow *fq_flow_get_default_func(struct fq *fq,
- struct fq_tin *tin,
- int idx,
- struct sk_buff *skb)
-{
- struct txq_info *txqi;
-
- txqi = container_of(tin, struct txq_info, tin);
- return &txqi->def_flow;
-}
-
static void ieee80211_txq_enqueue(struct ieee80211_local *local,
struct txq_info *txqi,
struct sk_buff *skb)
@@ -1415,8 +1404,7 @@ static void ieee80211_txq_enqueue(struct
spin_lock_bh(&fq->lock);
fq_tin_enqueue(fq, tin, flow_idx, skb,
- fq_skb_free_func,
- fq_flow_get_default_func);
+ fq_skb_free_func);
spin_unlock_bh(&fq->lock);
}
@@ -1459,7 +1447,6 @@ void ieee80211_txq_init(struct ieee80211
struct txq_info *txqi, int tid)
{
fq_tin_init(&txqi->tin);
- fq_flow_init(&txqi->def_flow);
codel_vars_init(&txqi->def_cvars);
codel_stats_init(&txqi->cstats);
__skb_queue_head_init(&txqi->frags);
@@ -3310,8 +3297,7 @@ static bool ieee80211_amsdu_aggregate(st
*/
tin = &txqi->tin;
- flow = fq_flow_classify(fq, tin, flow_idx, skb,
- fq_flow_get_default_func);
+ flow = fq_flow_classify(fq, tin, flow_idx, skb);
head = skb_peek_tail(&flow->queue);
if (!head || skb_is_gso(head))
goto out;

View File

@ -1,31 +0,0 @@
From: Dan Carpenter <dan.carpenter@oracle.com>
Date: Tue, 26 Nov 2019 15:09:39 +0300
Subject: [PATCH] mac80211: airtime: Fix an off by one in
ieee80211_calc_rx_airtime()
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
This code was copied from mt76 and inherited an off by one bug from
there. The > should be >= so that we don't read one element beyond
the end of the array.
Fixes: db3e1c40cf2f ("mac80211: Import airtime calculation code from mt76")
Reported-by: Toke Høiland-Jørgensen <toke@redhat.com>
Signed-off-by: Dan Carpenter <dan.carpenter@oracle.com>
Acked-by: Toke Høiland-Jørgensen <toke@redhat.com>
Link: https://lore.kernel.org/r/20191126120910.ftr4t7me3by32aiz@kili.mountain
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
---
--- a/net/mac80211/airtime.c
+++ b/net/mac80211/airtime.c
@@ -442,7 +442,7 @@ u32 ieee80211_calc_rx_airtime(struct iee
return 0;
sband = hw->wiphy->bands[status->band];
- if (!sband || status->rate_idx > sband->n_bitrates)
+ if (!sband || status->rate_idx >= sband->n_bitrates)
return 0;
rate = &sband->bitrates[status->rate_idx];

View File

@ -0,0 +1,317 @@
From: Felix Fietkau <nbd@nbd.name>
Date: Wed, 25 Nov 2020 18:10:34 +0100
Subject: [PATCH] net/fq_impl: do not maintain a backlog-sorted list of
flows
A sorted flow list is only needed to drop packets in the biggest flow when
hitting the overmemory condition.
By scanning flows only when needed, we can avoid paying the cost of
maintaining the list under normal conditions
In order to avoid scanning lots of empty flows and touching too many cold
cache lines, a bitmap of flows with backlog is maintained
Signed-off-by: Felix Fietkau <nbd@nbd.name>
---
--- a/include/net/fq.h
+++ b/include/net/fq.h
@@ -19,8 +19,6 @@ struct fq_tin;
* @flowchain: can be linked to fq_tin's new_flows or old_flows. Used for DRR++
* (deficit round robin) based round robin queuing similar to the one
* found in net/sched/sch_fq_codel.c
- * @backlogchain: can be linked to other fq_flow and fq. Used to keep track of
- * fat flows and efficient head-dropping if packet limit is reached
* @queue: sk_buff queue to hold packets
* @backlog: number of bytes pending in the queue. The number of packets can be
* found in @queue.qlen
@@ -29,7 +27,6 @@ struct fq_tin;
struct fq_flow {
struct fq_tin *tin;
struct list_head flowchain;
- struct list_head backlogchain;
struct sk_buff_head queue;
u32 backlog;
int deficit;
@@ -47,6 +44,7 @@ struct fq_flow {
struct fq_tin {
struct list_head new_flows;
struct list_head old_flows;
+ struct list_head tin_list;
struct fq_flow default_flow;
u32 backlog_bytes;
u32 backlog_packets;
@@ -60,14 +58,14 @@ struct fq_tin {
/**
* struct fq - main container for fair queuing purposes
*
- * @backlogs: linked to fq_flows. Used to maintain fat flows for efficient
- * head-dropping when @backlog reaches @limit
* @limit: max number of packets that can be queued across all flows
* @backlog: number of packets queued across all flows
*/
struct fq {
struct fq_flow *flows;
- struct list_head backlogs;
+ unsigned long *flows_bitmap;
+
+ struct list_head tin_backlog;
spinlock_t lock;
u32 flows_cnt;
u32 limit;
--- a/include/net/fq_impl.h
+++ b/include/net/fq_impl.h
@@ -17,12 +17,24 @@ __fq_adjust_removal(struct fq *fq, struc
unsigned int bytes, unsigned int truesize)
{
struct fq_tin *tin = flow->tin;
+ int idx;
tin->backlog_bytes -= bytes;
tin->backlog_packets -= packets;
flow->backlog -= bytes;
fq->backlog -= packets;
fq->memory_usage -= truesize;
+
+ if (flow->backlog)
+ return;
+
+ if (flow == &tin->default_flow) {
+ list_del_init(&tin->tin_list);
+ return;
+ }
+
+ idx = flow - fq->flows;
+ __clear_bit(idx, fq->flows_bitmap);
}
static void fq_adjust_removal(struct fq *fq,
@@ -32,24 +44,6 @@ static void fq_adjust_removal(struct fq
__fq_adjust_removal(fq, flow, 1, skb->len, skb->truesize);
}
-static void fq_rejigger_backlog(struct fq *fq, struct fq_flow *flow)
-{
- struct fq_flow *i;
-
- if (flow->backlog == 0) {
- list_del_init(&flow->backlogchain);
- } else {
- i = flow;
-
- list_for_each_entry_continue(i, &fq->backlogs, backlogchain)
- if (i->backlog < flow->backlog)
- break;
-
- list_move_tail(&flow->backlogchain,
- &i->backlogchain);
- }
-}
-
static struct sk_buff *fq_flow_dequeue(struct fq *fq,
struct fq_flow *flow)
{
@@ -62,7 +56,6 @@ static struct sk_buff *fq_flow_dequeue(s
return NULL;
fq_adjust_removal(fq, flow, skb);
- fq_rejigger_backlog(fq, flow);
return skb;
}
@@ -90,7 +83,6 @@ static int fq_flow_drop(struct fq *fq, s
} while (packets < pending);
__fq_adjust_removal(fq, flow, packets, bytes, truesize);
- fq_rejigger_backlog(fq, flow);
return packets;
}
@@ -170,22 +162,36 @@ static struct fq_flow *fq_flow_classify(
return flow;
}
-static void fq_recalc_backlog(struct fq *fq,
- struct fq_tin *tin,
- struct fq_flow *flow)
-{
- struct fq_flow *i;
-
- if (list_empty(&flow->backlogchain))
- list_add_tail(&flow->backlogchain, &fq->backlogs);
-
- i = flow;
- list_for_each_entry_continue_reverse(i, &fq->backlogs,
- backlogchain)
- if (i->backlog > flow->backlog)
- break;
+static struct fq_flow *fq_find_fattest_flow(struct fq *fq)
+{
+ struct fq_tin *tin;
+ struct fq_flow *flow = NULL;
+ u32 len = 0;
+ int i;
+
+ for_each_set_bit(i, fq->flows_bitmap, fq->flows_cnt) {
+ struct fq_flow *cur = &fq->flows[i];
+ unsigned int cur_len;
+
+ cur_len = cur->backlog;
+ if (cur_len <= len)
+ continue;
+
+ flow = cur;
+ len = cur_len;
+ }
- list_move(&flow->backlogchain, &i->backlogchain);
+ list_for_each_entry(tin, &fq->tin_backlog, tin_list) {
+ unsigned int cur_len = tin->default_flow.backlog;
+
+ if (cur_len <= len)
+ continue;
+
+ flow = &tin->default_flow;
+ len = cur_len;
+ }
+
+ return flow;
}
static void fq_tin_enqueue(struct fq *fq,
@@ -200,6 +206,13 @@ static void fq_tin_enqueue(struct fq *fq
flow = fq_flow_classify(fq, tin, idx, skb);
+ if (!flow->backlog) {
+ if (flow != &tin->default_flow)
+ __set_bit(idx, fq->flows_bitmap);
+ else if (list_empty(&tin->tin_list))
+ list_add(&tin->tin_list, &fq->tin_backlog);
+ }
+
flow->tin = tin;
flow->backlog += skb->len;
tin->backlog_bytes += skb->len;
@@ -207,8 +220,6 @@ static void fq_tin_enqueue(struct fq *fq
fq->memory_usage += skb->truesize;
fq->backlog++;
- fq_recalc_backlog(fq, tin, flow);
-
if (list_empty(&flow->flowchain)) {
flow->deficit = fq->quantum;
list_add_tail(&flow->flowchain,
@@ -218,9 +229,7 @@ static void fq_tin_enqueue(struct fq *fq
__skb_queue_tail(&flow->queue, skb);
oom = (fq->memory_usage > fq->memory_limit);
while (fq->backlog > fq->limit || oom) {
- flow = list_first_entry_or_null(&fq->backlogs,
- struct fq_flow,
- backlogchain);
+ flow = fq_find_fattest_flow(fq);
if (!flow)
return;
@@ -255,8 +264,6 @@ static void fq_flow_filter(struct fq *fq
fq_adjust_removal(fq, flow, skb);
free_func(fq, tin, flow, skb);
}
-
- fq_rejigger_backlog(fq, flow);
}
static void fq_tin_filter(struct fq *fq,
@@ -279,16 +286,18 @@ static void fq_flow_reset(struct fq *fq,
struct fq_flow *flow,
fq_skb_free_t free_func)
{
+ struct fq_tin *tin = flow->tin;
struct sk_buff *skb;
while ((skb = fq_flow_dequeue(fq, flow)))
- free_func(fq, flow->tin, flow, skb);
+ free_func(fq, tin, flow, skb);
- if (!list_empty(&flow->flowchain))
+ if (!list_empty(&flow->flowchain)) {
list_del_init(&flow->flowchain);
-
- if (!list_empty(&flow->backlogchain))
- list_del_init(&flow->backlogchain);
+ if (list_empty(&tin->new_flows) &&
+ list_empty(&tin->old_flows))
+ list_del_init(&tin->tin_list);
+ }
flow->tin = NULL;
@@ -314,6 +323,7 @@ static void fq_tin_reset(struct fq *fq,
fq_flow_reset(fq, flow, free_func);
}
+ WARN_ON_ONCE(!list_empty(&tin->tin_list));
WARN_ON_ONCE(tin->backlog_bytes);
WARN_ON_ONCE(tin->backlog_packets);
}
@@ -321,7 +331,6 @@ static void fq_tin_reset(struct fq *fq,
static void fq_flow_init(struct fq_flow *flow)
{
INIT_LIST_HEAD(&flow->flowchain);
- INIT_LIST_HEAD(&flow->backlogchain);
__skb_queue_head_init(&flow->queue);
}
@@ -329,6 +338,7 @@ static void fq_tin_init(struct fq_tin *t
{
INIT_LIST_HEAD(&tin->new_flows);
INIT_LIST_HEAD(&tin->old_flows);
+ INIT_LIST_HEAD(&tin->tin_list);
fq_flow_init(&tin->default_flow);
}
@@ -337,8 +347,8 @@ static int fq_init(struct fq *fq, int fl
int i;
memset(fq, 0, sizeof(fq[0]));
- INIT_LIST_HEAD(&fq->backlogs);
spin_lock_init(&fq->lock);
+ INIT_LIST_HEAD(&fq->tin_backlog);
fq->flows_cnt = max_t(u32, flows_cnt, 1);
fq->quantum = 300;
fq->limit = 8192;
@@ -348,6 +358,14 @@ static int fq_init(struct fq *fq, int fl
if (!fq->flows)
return -ENOMEM;
+ fq->flows_bitmap = kcalloc(BITS_TO_LONGS(fq->flows_cnt), sizeof(long),
+ GFP_KERNEL);
+ if (!fq->flows_bitmap) {
+ kvfree(fq->flows);
+ fq->flows = NULL;
+ return -ENOMEM;
+ }
+
for (i = 0; i < fq->flows_cnt; i++)
fq_flow_init(&fq->flows[i]);
@@ -364,6 +382,9 @@ static void fq_reset(struct fq *fq,
kvfree(fq->flows);
fq->flows = NULL;
+
+ kfree(fq->flows_bitmap);
+ fq->flows_bitmap = NULL;
}
#endif
--- a/net/mac80211/tx.c
+++ b/net/mac80211/tx.c
@@ -3364,8 +3364,6 @@ out_recalc:
if (head->len != orig_len) {
flow->backlog += head->len - orig_len;
tin->backlog_bytes += head->len - orig_len;
-
- fq_recalc_backlog(fq, tin, flow);
}
out:
spin_unlock_bh(&fq->lock);

Some files were not shown because too many files have changed in this diff Show More