Merge Official Source

This commit is contained in:
CN_SZTL 2020-08-23 01:08:37 +08:00
commit 008fd8bf4f
No known key found for this signature in database
GPG Key ID: 6850B6345C862176
33 changed files with 3417 additions and 578 deletions

View File

@ -0,0 +1,651 @@
From: Felix Fietkau <nbd@nbd.name>
Date: Thu, 13 Aug 2020 15:37:11 +0200
Subject: [PATCH] mac80211: rework tx encapsulation offload API
The current API (which lets the driver turn on/off per vif directly) has a
number of limitations:
- it does not deal with AP_VLAN
- conditions for enabling (no tkip, no monitor) are only checked at
add_interface time
- no way to indicate 4-addr support
In order to address this, store offload flags in struct ieee80211_vif
(easy to extend for decap offload later). mac80211 initially sets the enable
flag, but gives the driver a chance to modify it before its settings are
applied. In addition to the .add_interface op, a .update_vif_offload op is
introduced, which can be used for runtime changes.
If a driver can't disable encap offload at runtime, or if it has some extra
limitations, it can simply override the flags within those ops.
Support for encap offload with 4-address mode interfaces can be enabled
by setting a flag from .add_interface or .update_vif_offload.
Signed-off-by: Felix Fietkau <nbd@nbd.name>
---
--- a/drivers/net/wireless/ath/ath11k/mac.c
+++ b/drivers/net/wireless/ath/ath11k/mac.c
@@ -4150,6 +4150,35 @@ static int ath11k_set_he_mu_sounding_mod
return ret;
}
+static void ath11k_mac_op_update_vif_offload(struct ieee80211_hw *hw,
+ struct ieee80211_vif *vif)
+{
+ struct ath11k *ar = hw->priv;
+ struct ath11k_base *ab = ar->ab;
+ struct ath11k_vif *arvif = ath11k_vif_to_arvif(vif);
+ u32 param_id, param_value;
+ int ret;
+
+ param_id = WMI_VDEV_PARAM_TX_ENCAP_TYPE;
+ if (ath11k_frame_mode != ATH11K_HW_TXRX_ETHERNET ||
+ (vif->type != NL80211_IFTYPE_STATION &&
+ vif->type != NL80211_IFTYPE_AP))
+ vif->offload_flags &= ~IEEE80211_OFFLOAD_ENCAP_ENABLED;
+
+ if (vif->offload_flags & IEEE80211_OFFLOAD_ENCAP_ENABLED)
+ param_value = ATH11K_HW_TXRX_ETHERNET;
+ else
+ param_value = ATH11K_HW_TXRX_NATIVE_WIFI;
+
+ ret = ath11k_wmi_vdev_set_param_cmd(ar, arvif->vdev_id,
+ param_id, param_value);
+ if (ret) {
+ ath11k_warn(ab, "failed to set vdev %d tx encap mode: %d\n",
+ arvif->vdev_id, ret);
+ vif->offload_flags &= ~IEEE80211_OFFLOAD_ENCAP_ENABLED;
+ }
+}
+
static int ath11k_mac_op_add_interface(struct ieee80211_hw *hw,
struct ieee80211_vif *vif)
{
@@ -4159,7 +4188,6 @@ static int ath11k_mac_op_add_interface(s
struct vdev_create_params vdev_param = {0};
struct peer_create_params peer_param;
u32 param_id, param_value;
- int hw_encap = 0;
u16 nss;
int i;
int ret;
@@ -4253,30 +4281,7 @@ static int ath11k_mac_op_add_interface(s
list_add(&arvif->list, &ar->arvifs);
spin_unlock_bh(&ar->data_lock);
- param_id = WMI_VDEV_PARAM_TX_ENCAP_TYPE;
- if (ath11k_frame_mode == ATH11K_HW_TXRX_ETHERNET)
- switch (vif->type) {
- case NL80211_IFTYPE_STATION:
- case NL80211_IFTYPE_AP_VLAN:
- case NL80211_IFTYPE_AP:
- hw_encap = 1;
- break;
- default:
- break;
- }
-
- if (ieee80211_set_hw_80211_encap(vif, hw_encap))
- param_value = ATH11K_HW_TXRX_ETHERNET;
- else
- param_value = ATH11K_HW_TXRX_NATIVE_WIFI;
-
- ret = ath11k_wmi_vdev_set_param_cmd(ar, arvif->vdev_id,
- param_id, param_value);
- if (ret) {
- ath11k_warn(ab, "failed to set vdev %d tx encap mode: %d\n",
- arvif->vdev_id, ret);
- goto err_vdev_del;
- }
+ ath11k_mac_op_update_vif_offload(hw, vif);
nss = get_num_chains(ar->cfg_tx_chainmask) ? : 1;
ret = ath11k_wmi_vdev_set_param_cmd(ar, arvif->vdev_id,
@@ -5599,6 +5604,7 @@ static const struct ieee80211_ops ath11k
.reconfig_complete = ath11k_mac_op_reconfig_complete,
.add_interface = ath11k_mac_op_add_interface,
.remove_interface = ath11k_mac_op_remove_interface,
+ .update_vif_offload = ath11k_mac_op_update_vif_offload,
.config = ath11k_mac_op_config,
.bss_info_changed = ath11k_mac_op_bss_info_changed,
.configure_filter = ath11k_mac_op_configure_filter,
@@ -5852,6 +5858,7 @@ static int __ath11k_mac_register(struct
ieee80211_hw_set(ar->hw, QUEUE_CONTROL);
ieee80211_hw_set(ar->hw, SUPPORTS_TX_FRAG);
ieee80211_hw_set(ar->hw, REPORTS_LOW_ACK);
+ ieee80211_hw_set(ar->hw, SUPPORTS_TX_ENCAP_OFFLOAD);
if (ht_cap & WMI_HT_CAP_ENABLED) {
ieee80211_hw_set(ar->hw, AMPDU_AGGREGATION);
ieee80211_hw_set(ar->hw, TX_AMPDU_SETUP_IN_HW);
--- a/include/net/mac80211.h
+++ b/include/net/mac80211.h
@@ -1603,6 +1603,21 @@ enum ieee80211_vif_flags {
IEEE80211_VIF_GET_NOA_UPDATE = BIT(3),
};
+
+/**
+ * enum ieee80211_offload_flags - virtual interface offload flags
+ *
+ * @IEEE80211_OFFLOAD_ENCAP_ENABLED: tx encapsulation offload is enabled
+ * The driver supports sending frames passed as 802.3 frames by mac80211.
+ * It must also support sending 802.11 packets for the same interface.
+ * @IEEE80211_OFFLOAD_ENCAP_4ADDR: support 4-address mode encapsulation offload
+ */
+
+enum ieee80211_offload_flags {
+ IEEE80211_OFFLOAD_ENCAP_ENABLED = BIT(0),
+ IEEE80211_OFFLOAD_ENCAP_4ADDR = BIT(1),
+};
+
/**
* struct ieee80211_vif - per-interface data
*
@@ -1623,6 +1638,11 @@ enum ieee80211_vif_flags {
* these need to be set (or cleared) when the interface is added
* or, if supported by the driver, the interface type is changed
* at runtime, mac80211 will never touch this field
+ * @offloaad_flags: hardware offload capabilities/flags for this interface.
+ * These are initialized by mac80211 before calling .add_interface,
+ * .change_interface or .update_vif_offload and updated by the driver
+ * within these ops, based on supported features or runtime change
+ * restrictions.
* @hw_queue: hardware queue for each AC
* @cab_queue: content-after-beacon (DTIM beacon really) queue, AP mode only
* @chanctx_conf: The channel context this interface is assigned to, or %NULL
@@ -1659,6 +1679,7 @@ struct ieee80211_vif {
struct ieee80211_chanctx_conf __rcu *chanctx_conf;
u32 driver_flags;
+ u32 offload_flags;
#ifdef CPTCFG_MAC80211_DEBUGFS
struct dentry *debugfs_dir;
@@ -2325,6 +2346,9 @@ struct ieee80211_txq {
* aggregating MPDUs with the same keyid, allowing mac80211 to keep Tx
* A-MPDU sessions active while rekeying with Extended Key ID.
*
+ * @IEEE80211_HW_SUPPORTS_TX_ENCAP_OFFLOAD: Hardware supports tx encapsulation
+ * offload
+ *
* @NUM_IEEE80211_HW_FLAGS: number of hardware flags, used for sizing arrays
*/
enum ieee80211_hw_flags {
@@ -2377,6 +2401,7 @@ enum ieee80211_hw_flags {
IEEE80211_HW_SUPPORTS_MULTI_BSSID,
IEEE80211_HW_SUPPORTS_ONLY_HE_MULTI_BSSID,
IEEE80211_HW_AMPDU_KEYBORDER_SUPPORT,
+ IEEE80211_HW_SUPPORTS_TX_ENCAP_OFFLOAD,
/* keep last, obviously */
NUM_IEEE80211_HW_FLAGS
@@ -3811,6 +3836,8 @@ enum ieee80211_reconfig_type {
* @set_tid_config: Apply TID specific configurations. This callback may sleep.
* @reset_tid_config: Reset TID specific configuration for the peer.
* This callback may sleep.
+ * @update_vif_config: Update virtual interface offload flags
+ * This callback may sleep.
*/
struct ieee80211_ops {
void (*tx)(struct ieee80211_hw *hw,
@@ -4122,6 +4149,8 @@ struct ieee80211_ops {
int (*reset_tid_config)(struct ieee80211_hw *hw,
struct ieee80211_vif *vif,
struct ieee80211_sta *sta, u8 tids);
+ void (*update_vif_offload)(struct ieee80211_hw *hw,
+ struct ieee80211_vif *vif);
};
/**
--- a/net/mac80211/cfg.c
+++ b/net/mac80211/cfg.c
@@ -504,6 +504,7 @@ static int ieee80211_del_key(struct wiph
struct ieee80211_local *local = sdata->local;
struct sta_info *sta;
struct ieee80211_key *key = NULL;
+ bool recalc_offload = false;
int ret;
mutex_lock(&local->sta_mtx);
@@ -528,6 +529,7 @@ static int ieee80211_del_key(struct wiph
goto out_unlock;
}
+ recalc_offload = key->conf.cipher == WLAN_CIPHER_SUITE_TKIP;
ieee80211_key_free(key, sdata->vif.type == NL80211_IFTYPE_STATION);
ret = 0;
@@ -535,6 +537,9 @@ static int ieee80211_del_key(struct wiph
mutex_unlock(&local->key_mtx);
mutex_unlock(&local->sta_mtx);
+ if (recalc_offload)
+ ieee80211_recalc_offload(local);
+
return ret;
}
--- a/net/mac80211/debugfs.c
+++ b/net/mac80211/debugfs.c
@@ -408,6 +408,7 @@ static const char *hw_flag_names[] = {
FLAG(SUPPORTS_MULTI_BSSID),
FLAG(SUPPORTS_ONLY_HE_MULTI_BSSID),
FLAG(AMPDU_KEYBORDER_SUPPORT),
+ FLAG(SUPPORTS_TX_ENCAP_OFFLOAD),
#undef FLAG
};
--- a/net/mac80211/driver-ops.h
+++ b/net/mac80211/driver-ops.h
@@ -1385,4 +1385,19 @@ static inline int drv_reset_tid_config(s
return ret;
}
+
+static inline void drv_update_vif_offload(struct ieee80211_local *local,
+ struct ieee80211_sub_if_data *sdata)
+{
+ might_sleep();
+ check_sdata_in_driver(sdata);
+
+ if (!local->ops->update_vif_offload)
+ return;
+
+ trace_drv_update_vif_offload(local, sdata);
+ local->ops->update_vif_offload(&local->hw, &sdata->vif);
+ trace_drv_return_void(local);
+}
+
#endif /* __MAC80211_DRIVER_OPS */
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -990,8 +990,6 @@ struct ieee80211_sub_if_data {
} debugfs;
#endif
- bool hw_80211_encap;
-
/* must be last, dynamically sized area in this! */
struct ieee80211_vif vif;
};
@@ -1769,6 +1767,7 @@ void ieee80211_del_virtual_monitor(struc
bool __ieee80211_recalc_txpower(struct ieee80211_sub_if_data *sdata);
void ieee80211_recalc_txpower(struct ieee80211_sub_if_data *sdata,
bool update_bss);
+void ieee80211_recalc_offload(struct ieee80211_local *local);
static inline bool ieee80211_sdata_running(struct ieee80211_sub_if_data *sdata)
{
--- a/net/mac80211/iface.c
+++ b/net/mac80211/iface.c
@@ -43,6 +43,7 @@
*/
static void ieee80211_iface_work(struct work_struct *work);
+static void ieee80211_set_vif_encap_ops(struct ieee80211_sub_if_data *sdata);
bool __ieee80211_recalc_txpower(struct ieee80211_sub_if_data *sdata)
{
@@ -348,6 +349,99 @@ static int ieee80211_check_queues(struct
return 0;
}
+static bool ieee80211_iftype_supports_encap_offload(enum nl80211_iftype iftype)
+{
+ switch (iftype) {
+ case NL80211_IFTYPE_AP:
+ case NL80211_IFTYPE_P2P_GO:
+ case NL80211_IFTYPE_P2P_CLIENT:
+ case NL80211_IFTYPE_STATION:
+ return true;
+ default:
+ return false;
+ }
+}
+
+static bool ieee80211_set_sdata_offload_flags(struct ieee80211_sub_if_data *sdata)
+{
+ struct ieee80211_local *local = sdata->local;
+ struct ieee80211_key *key;
+ u32 flags;
+
+ flags = sdata->vif.offload_flags;
+
+ if (ieee80211_hw_check(&local->hw, SUPPORTS_TX_ENCAP_OFFLOAD) &&
+ ieee80211_iftype_supports_encap_offload(sdata->vif.type)) {
+ flags |= IEEE80211_OFFLOAD_ENCAP_ENABLED;
+ mutex_lock(&local->key_mtx);
+ list_for_each_entry(key, &sdata->key_list, list) {
+ if (key->conf.cipher == WLAN_CIPHER_SUITE_AES_CMAC ||
+ key->conf.cipher == WLAN_CIPHER_SUITE_BIP_GMAC_128 ||
+ key->conf.cipher == WLAN_CIPHER_SUITE_BIP_GMAC_256 ||
+ key->conf.cipher == WLAN_CIPHER_SUITE_BIP_CMAC_256)
+ continue;
+ if (key->conf.cipher == WLAN_CIPHER_SUITE_TKIP ||
+ !(key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE))
+ flags &= ~IEEE80211_OFFLOAD_ENCAP_ENABLED;
+ }
+ mutex_unlock(&local->key_mtx);
+
+ if (!ieee80211_hw_check(&local->hw, SUPPORTS_TX_FRAG) &&
+ local->hw.wiphy->frag_threshold != (u32)-1)
+ flags &= ~IEEE80211_OFFLOAD_ENCAP_ENABLED;
+
+ if (local->monitors)
+ flags &= ~IEEE80211_OFFLOAD_ENCAP_ENABLED;
+ } else {
+ flags &= ~IEEE80211_OFFLOAD_ENCAP_ENABLED;
+ }
+
+ if (sdata->vif.offload_flags == flags)
+ return false;
+
+ sdata->vif.offload_flags = flags;
+ return true;
+}
+
+
+static void ieee80211_recalc_sdata_offload(struct ieee80211_sub_if_data *sdata)
+{
+ struct ieee80211_local *local = sdata->local;
+ struct ieee80211_sub_if_data *vsdata;
+
+ if (ieee80211_set_sdata_offload_flags(sdata)) {
+ drv_update_vif_offload(local, sdata);
+ ieee80211_set_vif_encap_ops(sdata);
+ }
+
+ list_for_each_entry(vsdata, &local->interfaces, list) {
+ if (vsdata->vif.type != NL80211_IFTYPE_AP_VLAN ||
+ vsdata->bss != &sdata->u.ap)
+ continue;
+
+ ieee80211_set_vif_encap_ops(vsdata);
+ }
+}
+
+void ieee80211_recalc_offload(struct ieee80211_local *local)
+{
+ struct ieee80211_sub_if_data *sdata;
+
+ if (!ieee80211_hw_check(&local->hw, SUPPORTS_TX_ENCAP_OFFLOAD))
+ return;
+
+ mutex_lock(&local->iflist_mtx);
+
+ list_for_each_entry(sdata, &local->interfaces, list) {
+ if (!ieee80211_sdata_running(sdata))
+ continue;
+
+ ieee80211_recalc_sdata_offload(sdata);
+ }
+
+ mutex_unlock(&local->iflist_mtx);
+}
+
void ieee80211_adjust_monitor_flags(struct ieee80211_sub_if_data *sdata,
const int offset)
{
@@ -587,6 +681,7 @@ int ieee80211_do_open(struct wireless_de
if (rtnl_dereference(sdata->bss->beacon)) {
ieee80211_vif_vlan_copy_chanctx(sdata);
netif_carrier_on(dev);
+ ieee80211_set_vif_encap_ops(sdata);
} else {
netif_carrier_off(dev);
}
@@ -616,6 +711,7 @@ int ieee80211_do_open(struct wireless_de
ieee80211_adjust_monitor_flags(sdata, 1);
ieee80211_configure_filter(local);
+ ieee80211_recalc_offload(local);
mutex_lock(&local->mtx);
ieee80211_recalc_idle(local);
mutex_unlock(&local->mtx);
@@ -625,10 +721,13 @@ int ieee80211_do_open(struct wireless_de
default:
if (coming_up) {
ieee80211_del_virtual_monitor(local);
+ ieee80211_set_sdata_offload_flags(sdata);
res = drv_add_interface(local, sdata);
if (res)
goto err_stop;
+
+ ieee80211_set_vif_encap_ops(sdata);
res = ieee80211_check_queues(sdata,
ieee80211_vif_type_p2p(&sdata->vif));
if (res)
@@ -1286,61 +1385,6 @@ static const struct net_device_ops ieee8
};
-static void __ieee80211_set_hw_80211_encap(struct ieee80211_sub_if_data *sdata,
- bool enable)
-{
- sdata->dev->netdev_ops = enable ? &ieee80211_dataif_8023_ops :
- &ieee80211_dataif_ops;
- sdata->hw_80211_encap = enable;
-}
-
-bool ieee80211_set_hw_80211_encap(struct ieee80211_vif *vif, bool enable)
-{
- struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif);
- struct ieee80211_local *local = sdata->local;
- struct ieee80211_sub_if_data *iter;
- struct ieee80211_key *key;
-
- mutex_lock(&local->iflist_mtx);
- list_for_each_entry(iter, &local->interfaces, list) {
- struct ieee80211_sub_if_data *disable = NULL;
-
- if (vif->type == NL80211_IFTYPE_MONITOR) {
- disable = iter;
- __ieee80211_set_hw_80211_encap(iter, false);
- } else if (iter->vif.type == NL80211_IFTYPE_MONITOR) {
- disable = sdata;
- enable = false;
- }
- if (disable)
- sdata_dbg(disable,
- "disable hw 80211 encap due to mon co-exist\n");
- }
- mutex_unlock(&local->iflist_mtx);
-
- if (enable == sdata->hw_80211_encap)
- return enable;
-
- if (!sdata->dev)
- return false;
-
- if (!ieee80211_hw_check(&local->hw, SUPPORTS_TX_FRAG) &&
- (local->hw.wiphy->frag_threshold != (u32)-1))
- enable = false;
-
- mutex_lock(&sdata->local->key_mtx);
- list_for_each_entry(key, &sdata->key_list, list) {
- if (key->conf.cipher == WLAN_CIPHER_SUITE_TKIP)
- enable = false;
- }
- mutex_unlock(&sdata->local->key_mtx);
-
- __ieee80211_set_hw_80211_encap(sdata, enable);
-
- return enable;
-}
-EXPORT_SYMBOL(ieee80211_set_hw_80211_encap);
-
static void ieee80211_if_free(struct net_device *dev)
{
free_percpu(netdev_tstats(dev));
@@ -1371,6 +1415,51 @@ static void ieee80211_if_setup_no_queue(
#endif
}
+static void ieee80211_set_vif_encap_ops(struct ieee80211_sub_if_data *sdata)
+{
+ struct ieee80211_local *local = sdata->local;
+ struct ieee80211_sub_if_data *bss = sdata;
+ struct ieee80211_key *key;
+ bool enabled;
+
+ if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN) {
+ if (!sdata->bss)
+ return;
+
+ bss = container_of(sdata->bss, struct ieee80211_sub_if_data, u.ap);
+ }
+
+ if (!ieee80211_hw_check(&local->hw, SUPPORTS_TX_ENCAP_OFFLOAD) ||
+ !ieee80211_iftype_supports_encap_offload(bss->vif.type))
+ return;
+
+ enabled = bss->vif.offload_flags & IEEE80211_OFFLOAD_ENCAP_ENABLED;
+ if (sdata->wdev.use_4addr &&
+ !(bss->vif.offload_flags & IEEE80211_OFFLOAD_ENCAP_4ADDR))
+ enabled = false;
+
+ /*
+ * Encapsulation offload cannot be used with software crypto, and a per-VLAN
+ * key may have been set
+ */
+ if (enabled && sdata->vif.type == NL80211_IFTYPE_AP_VLAN) {
+ mutex_lock(&local->key_mtx);
+ list_for_each_entry(key, &sdata->key_list, list) {
+ if (key->conf.cipher == WLAN_CIPHER_SUITE_AES_CMAC ||
+ key->conf.cipher == WLAN_CIPHER_SUITE_BIP_GMAC_128 ||
+ key->conf.cipher == WLAN_CIPHER_SUITE_BIP_GMAC_256 ||
+ key->conf.cipher == WLAN_CIPHER_SUITE_BIP_CMAC_256)
+ continue;
+ if (!(key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE))
+ enabled = false;
+ }
+ mutex_unlock(&local->key_mtx);
+ }
+
+ sdata->dev->netdev_ops = enabled ? &ieee80211_dataif_8023_ops :
+ &ieee80211_dataif_ops;
+}
+
static void ieee80211_iface_work(struct work_struct *work)
{
struct ieee80211_sub_if_data *sdata =
@@ -1553,7 +1642,6 @@ static void ieee80211_setup_sdata(struct
sdata->vif.bss_conf.txpower = INT_MIN; /* unset */
sdata->noack_map = 0;
- sdata->hw_80211_encap = false;
/* only monitor/p2p-device differ */
if (sdata->dev) {
@@ -1688,6 +1776,7 @@ static int ieee80211_runtime_change_ifty
ieee80211_teardown_sdata(sdata);
+ ieee80211_set_sdata_offload_flags(sdata);
ret = drv_change_interface(local, sdata, internal_type, p2p);
if (ret)
type = ieee80211_vif_type_p2p(&sdata->vif);
@@ -1700,6 +1789,7 @@ static int ieee80211_runtime_change_ifty
ieee80211_check_queues(sdata, type);
ieee80211_setup_sdata(sdata, type);
+ ieee80211_set_vif_encap_ops(sdata);
err = ieee80211_do_open(&sdata->wdev, false);
WARN(err, "type change: do_open returned %d", err);
--- a/net/mac80211/key.c
+++ b/net/mac80211/key.c
@@ -177,13 +177,6 @@ static int ieee80211_key_enable_hw_accel
}
}
- /* TKIP countermeasures don't work in encap offload mode */
- if (key->conf.cipher == WLAN_CIPHER_SUITE_TKIP &&
- sdata->hw_80211_encap) {
- sdata_dbg(sdata, "TKIP is not allowed in hw 80211 encap mode\n");
- return -EINVAL;
- }
-
ret = drv_set_key(key->local, SET_KEY, sdata,
sta ? &sta->sta : NULL, &key->conf);
@@ -219,14 +212,6 @@ static int ieee80211_key_enable_hw_accel
case WLAN_CIPHER_SUITE_CCMP_256:
case WLAN_CIPHER_SUITE_GCMP:
case WLAN_CIPHER_SUITE_GCMP_256:
- /* We cannot do software crypto of data frames with
- * encapsulation offload enabled. However for 802.11w to
- * function properly we need cmac/gmac keys.
- */
- if (sdata->hw_80211_encap)
- return -EINVAL;
- /* Fall through */
-
case WLAN_CIPHER_SUITE_AES_CMAC:
case WLAN_CIPHER_SUITE_BIP_CMAC_256:
case WLAN_CIPHER_SUITE_BIP_GMAC_128:
@@ -824,6 +809,7 @@ int ieee80211_key_link(struct ieee80211_
*/
bool delay_tailroom = sdata->vif.type == NL80211_IFTYPE_STATION;
int ret = -EOPNOTSUPP;
+ bool recalc_offload = false;
mutex_lock(&sdata->local->key_mtx);
@@ -864,11 +850,15 @@ int ieee80211_key_link(struct ieee80211_
key->local = sdata->local;
key->sdata = sdata;
key->sta = sta;
+ recalc_offload = !old_key && key->conf.cipher == WLAN_CIPHER_SUITE_TKIP;
increment_tailroom_need_count(sdata);
ret = ieee80211_key_replace(sdata, sta, pairwise, old_key, key);
+ if (!(key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE))
+ recalc_offload = true;
+
if (!ret) {
ieee80211_debugfs_key_add(key);
ieee80211_key_destroy(old_key, delay_tailroom);
@@ -879,6 +869,9 @@ int ieee80211_key_link(struct ieee80211_
out:
mutex_unlock(&sdata->local->key_mtx);
+ if (recalc_offload)
+ ieee80211_recalc_offload(sdata->local);
+
return ret;
}
--- a/net/mac80211/trace.h
+++ b/net/mac80211/trace.h
@@ -2733,6 +2733,12 @@ TRACE_EVENT(drv_get_ftm_responder_stats,
)
);
+DEFINE_EVENT(local_sdata_addr_evt, drv_update_vif_offload,
+ TP_PROTO(struct ieee80211_local *local,
+ struct ieee80211_sub_if_data *sdata),
+ TP_ARGS(local, sdata)
+);
+
#endif /* !__MAC80211_DRIVER_TRACE || TRACE_HEADER_MULTI_READ */
#undef TRACE_INCLUDE_PATH
--- a/net/mac80211/tx.c
+++ b/net/mac80211/tx.c
@@ -4270,11 +4270,6 @@ netdev_tx_t ieee80211_subif_start_xmit_8
struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
struct sta_info *sta;
- if (WARN_ON(!sdata->hw_80211_encap)) {
- kfree_skb(skb);
- return NETDEV_TX_OK;
- }
-
if (unlikely(skb->len < ETH_HLEN)) {
kfree_skb(skb);
return NETDEV_TX_OK;

View File

@ -0,0 +1,197 @@
From: Felix Fietkau <nbd@nbd.name>
Date: Mon, 17 Aug 2020 13:16:59 +0200
Subject: [PATCH] mac80211: reduce duplication in tx status functions
Move redundant functionality from __ieee80211_tx_status into
ieee80211_tx_status_ext. Preparation for unifying with the 802.3 tx status
codepath.
Signed-off-by: Felix Fietkau <nbd@nbd.name>
---
--- a/net/mac80211/status.c
+++ b/net/mac80211/status.c
@@ -184,18 +184,6 @@ static void ieee80211_frame_acked(struct
struct ieee80211_mgmt *mgmt = (void *) skb->data;
struct ieee80211_local *local = sta->local;
struct ieee80211_sub_if_data *sdata = sta->sdata;
- struct ieee80211_tx_info *txinfo = IEEE80211_SKB_CB(skb);
-
- if (ieee80211_hw_check(&local->hw, REPORTS_TX_ACK_STATUS)) {
- sta->status_stats.last_ack = jiffies;
- if (txinfo->status.is_valid_ack_signal) {
- sta->status_stats.last_ack_signal =
- (s8)txinfo->status.ack_signal;
- sta->status_stats.ack_signal_filled = true;
- ewma_avg_signal_add(&sta->status_stats.avg_ack_signal,
- -txinfo->status.ack_signal);
- }
- }
if (ieee80211_is_data_qos(mgmt->frame_control)) {
struct ieee80211_hdr *hdr = (void *) skb->data;
@@ -899,7 +887,8 @@ void ieee80211_tx_monitor(struct ieee802
}
static void __ieee80211_tx_status(struct ieee80211_hw *hw,
- struct ieee80211_tx_status *status)
+ struct ieee80211_tx_status *status,
+ int rates_idx, int retry_count)
{
struct sk_buff *skb = status->skb;
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
@@ -908,8 +897,6 @@ static void __ieee80211_tx_status(struct
struct sta_info *sta;
__le16 fc;
struct ieee80211_supported_band *sband;
- int retry_count;
- int rates_idx;
bool send_to_cooked;
bool acked;
bool noack_success;
@@ -918,8 +905,6 @@ static void __ieee80211_tx_status(struct
int tid = IEEE80211_NUM_TIDS;
u16 tx_time_est;
- rates_idx = ieee80211_tx_get_rates(hw, info, &retry_count);
-
sband = local->hw.wiphy->bands[info->band];
fc = hdr->frame_control;
@@ -996,24 +981,14 @@ static void __ieee80211_tx_status(struct
if (info->flags & IEEE80211_TX_STAT_TX_FILTERED) {
ieee80211_handle_filtered_frame(local, sta, skb);
return;
- } else {
+ } else if (ieee80211_is_data_present(fc)) {
if (!acked && !noack_success)
- sta->status_stats.retry_failed++;
- sta->status_stats.retry_count += retry_count;
-
- if (ieee80211_is_data_present(fc)) {
- if (!acked && !noack_success)
- sta->status_stats.msdu_failed[tid]++;
+ sta->status_stats.msdu_failed[tid]++;
- sta->status_stats.msdu_retries[tid] +=
- retry_count;
- }
+ sta->status_stats.msdu_retries[tid] +=
+ retry_count;
}
- rate_control_tx_status(local, sband, status);
- if (ieee80211_vif_is_mesh(&sta->sdata->vif))
- ieee80211s_update_metric(local, sta, status);
-
if (!(info->flags & IEEE80211_TX_CTL_INJECTED) && acked)
ieee80211_frame_acked(sta, skb);
@@ -1038,20 +1013,6 @@ static void __ieee80211_tx_status(struct
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)
- sta->status_stats.lost_packets = 0;
-
- /* Track when last TDLS packet was ACKed */
- sta->status_stats.last_pkt_time = jiffies;
- } else if (noack_success) {
- /* nothing to do here, do not account as lost */
- } else {
- ieee80211_lost_packet(sta, info);
- }
- }
}
/* SNMP counters
@@ -1135,7 +1096,7 @@ void ieee80211_tx_status(struct ieee8021
if (sta)
status.sta = &sta->sta;
- __ieee80211_tx_status(hw, &status);
+ ieee80211_tx_status_ext(hw, &status);
rcu_read_unlock();
}
EXPORT_SYMBOL(ieee80211_tx_status);
@@ -1148,7 +1109,7 @@ void ieee80211_tx_status_ext(struct ieee
struct ieee80211_sta *pubsta = status->sta;
struct ieee80211_supported_band *sband;
struct sta_info *sta;
- int retry_count;
+ int rates_idx, retry_count;
bool acked, noack_success;
if (pubsta) {
@@ -1158,13 +1119,7 @@ void ieee80211_tx_status_ext(struct ieee
sta->tx_stats.last_rate_info = *status->rate;
}
- if (status->skb)
- return __ieee80211_tx_status(hw, status);
-
- if (!status->sta)
- return;
-
- ieee80211_tx_get_rates(hw, info, &retry_count);
+ rates_idx = ieee80211_tx_get_rates(hw, info, &retry_count);
sband = hw->wiphy->bands[info->band];
@@ -1176,20 +1131,30 @@ void ieee80211_tx_status_ext(struct ieee
sta->status_stats.retry_failed++;
sta->status_stats.retry_count += retry_count;
- if (acked) {
- sta->status_stats.last_ack = jiffies;
+ if (ieee80211_hw_check(&local->hw, REPORTS_TX_ACK_STATUS)) {
+ if (acked) {
+ sta->status_stats.last_ack = jiffies;
- if (sta->status_stats.lost_packets)
- sta->status_stats.lost_packets = 0;
+ if (sta->status_stats.lost_packets)
+ sta->status_stats.lost_packets = 0;
- /* Track when last packet was ACKed */
- sta->status_stats.last_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);
+ /* Track when last packet was ACKed */
+ sta->status_stats.last_pkt_time = jiffies;
+
+ if (info->status.is_valid_ack_signal) {
+ sta->status_stats.last_ack_signal =
+ (s8)info->status.ack_signal;
+ sta->status_stats.ack_signal_filled = true;
+ ewma_avg_signal_add(&sta->status_stats.avg_ack_signal,
+ -info->status.ack_signal);
+ }
+ } 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);
+ }
}
rate_control_tx_status(local, sband, status);
@@ -1197,6 +1162,10 @@ void ieee80211_tx_status_ext(struct ieee
ieee80211s_update_metric(local, sta, status);
}
+ if (status->skb)
+ return __ieee80211_tx_status(hw, status, rates_idx,
+ retry_count);
+
if (acked || noack_success) {
I802_DEBUG_INC(local->dot11TransmittedFrameCount);
if (!pubsta)

View File

@ -0,0 +1,26 @@
From: Felix Fietkau <nbd@nbd.name>
Date: Mon, 17 Aug 2020 13:29:12 +0200
Subject: [PATCH] mac80211: remove tx status call to
ieee80211_sta_register_airtime
All drivers using airtime fairness are calling ieee80211_sta_register_airtime
directly
Signed-off-by: Felix Fietkau <nbd@nbd.name>
---
--- a/net/mac80211/status.c
+++ b/net/mac80211/status.c
@@ -997,12 +997,6 @@ static void __ieee80211_tx_status(struct
ieee80211_sta_tx_notify(sta->sdata, (void *) skb->data,
acked, info->status.tx_time);
- if (info->status.tx_time &&
- wiphy_ext_feature_isset(local->hw.wiphy,
- NL80211_EXT_FEATURE_AIRTIME_FAIRNESS))
- 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().

View File

@ -0,0 +1,174 @@
From: Felix Fietkau <nbd@nbd.name>
Date: Mon, 17 Aug 2020 13:29:56 +0200
Subject: [PATCH] mac80211: optimize station connection monitor
Calling mod_timer for every rx/tx packet can be quite expensive.
Instead of constantly updating the timer, we can simply let it run out
and check the timestamp of the last ACK or rx packet to re-arm it.
Signed-off-by: Felix Fietkau <nbd@nbd.name>
---
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -2045,8 +2045,6 @@ void ieee80211_dynamic_ps_timer(struct t
void ieee80211_send_nullfunc(struct ieee80211_local *local,
struct ieee80211_sub_if_data *sdata,
bool powersave);
-void ieee80211_sta_rx_notify(struct ieee80211_sub_if_data *sdata,
- struct ieee80211_hdr *hdr);
void ieee80211_sta_tx_notify(struct ieee80211_sub_if_data *sdata,
struct ieee80211_hdr *hdr, bool ack, u16 tx_time);
--- a/net/mac80211/mlme.c
+++ b/net/mac80211/mlme.c
@@ -2432,23 +2432,6 @@ static void ieee80211_set_disassoc(struc
sdata->encrypt_headroom = IEEE80211_ENCRYPT_HEADROOM;
}
-void ieee80211_sta_rx_notify(struct ieee80211_sub_if_data *sdata,
- struct ieee80211_hdr *hdr)
-{
- /*
- * We can postpone the mgd.timer whenever receiving unicast frames
- * from AP because we know that the connection is working both ways
- * at that time. But multicast frames (and hence also beacons) must
- * be ignored here, because we need to trigger the timer during
- * data idle periods for sending the periodic probe request to the
- * AP we're connected to.
- */
- if (is_multicast_ether_addr(hdr->addr1))
- return;
-
- ieee80211_sta_reset_conn_monitor(sdata);
-}
-
static void ieee80211_reset_ap_probe(struct ieee80211_sub_if_data *sdata)
{
struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
@@ -2521,21 +2504,13 @@ void ieee80211_sta_tx_notify(struct ieee
{
ieee80211_sta_tx_wmm_ac_notify(sdata, hdr, tx_time);
- if (!ieee80211_is_data(hdr->frame_control))
- return;
-
- if (ieee80211_is_any_nullfunc(hdr->frame_control) &&
- sdata->u.mgd.probe_send_count > 0) {
- if (ack)
- ieee80211_sta_reset_conn_monitor(sdata);
- else
- sdata->u.mgd.nullfunc_failed = true;
- ieee80211_queue_work(&sdata->local->hw, &sdata->work);
+ if (!ieee80211_is_any_nullfunc(hdr->frame_control) ||
+ !sdata->u.mgd.probe_send_count)
return;
- }
- if (ack)
- ieee80211_sta_reset_conn_monitor(sdata);
+ if (!ack)
+ sdata->u.mgd.nullfunc_failed = true;
+ ieee80211_queue_work(&sdata->local->hw, &sdata->work);
}
static void ieee80211_mlme_send_probe_req(struct ieee80211_sub_if_data *sdata,
@@ -3600,8 +3575,8 @@ static bool ieee80211_assoc_success(stru
* Start timer to probe the connection to the AP now.
* Also start the timer that will detect beacon loss.
*/
- ieee80211_sta_rx_notify(sdata, (struct ieee80211_hdr *)mgmt);
ieee80211_sta_reset_beacon_monitor(sdata);
+ ieee80211_sta_reset_conn_monitor(sdata);
ret = true;
out:
@@ -4569,10 +4544,26 @@ static void ieee80211_sta_conn_mon_timer
from_timer(sdata, t, u.mgd.conn_mon_timer);
struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
struct ieee80211_local *local = sdata->local;
+ struct sta_info *sta;
+ unsigned long timeout;
if (sdata->vif.csa_active && !ifmgd->csa_waiting_bcn)
return;
+ sta = sta_info_get(sdata, ifmgd->bssid);
+ if (!sta)
+ return;
+
+ timeout = sta->status_stats.last_ack;
+ if (time_before(sta->status_stats.last_ack, sta->rx_stats.last_rx))
+ timeout = sta->rx_stats.last_rx;
+ timeout += IEEE80211_CONNECTION_IDLE_TIME;
+
+ if (time_is_before_jiffies(timeout)) {
+ mod_timer(&ifmgd->conn_mon_timer, round_jiffies_up(timeout));
+ return;
+ }
+
ieee80211_queue_work(&local->hw, &ifmgd->monitor_work);
}
--- a/net/mac80211/rx.c
+++ b/net/mac80211/rx.c
@@ -1811,9 +1811,6 @@ ieee80211_rx_h_sta_process(struct ieee80
sta->rx_stats.last_rate = sta_stats_encode_rate(status);
}
- if (rx->sdata->vif.type == NL80211_IFTYPE_STATION)
- ieee80211_sta_rx_notify(rx->sdata, hdr);
-
sta->rx_stats.fragments++;
u64_stats_update_begin(&rx->sta->rx_stats.syncp);
@@ -4148,7 +4145,6 @@ void ieee80211_check_fast_rx(struct sta_
fastrx.sa_offs = offsetof(struct ieee80211_hdr, addr2);
fastrx.expected_ds_bits = 0;
} else {
- fastrx.sta_notify = sdata->u.mgd.probe_send_count > 0;
fastrx.da_offs = offsetof(struct ieee80211_hdr, addr1);
fastrx.sa_offs = offsetof(struct ieee80211_hdr, addr3);
fastrx.expected_ds_bits =
@@ -4378,11 +4374,6 @@ static bool ieee80211_invoke_fast_rx(str
pskb_trim(skb, skb->len - fast_rx->icv_len))
goto drop;
- if (unlikely(fast_rx->sta_notify)) {
- ieee80211_sta_rx_notify(rx->sdata, hdr);
- fast_rx->sta_notify = false;
- }
-
/* statistics part of ieee80211_rx_h_sta_process() */
if (!(status->flag & RX_FLAG_NO_SIGNAL_VAL)) {
stats->last_signal = status->signal;
--- a/net/mac80211/sta_info.h
+++ b/net/mac80211/sta_info.h
@@ -336,7 +336,6 @@ struct ieee80211_fast_tx {
* @expected_ds_bits: from/to DS bits expected
* @icv_len: length of the MIC if present
* @key: bool indicating encryption is expected (key is set)
- * @sta_notify: notify the MLME code (once)
* @internal_forward: forward froms internally on AP/VLAN type interfaces
* @uses_rss: copy of USES_RSS hw flag
* @da_offs: offset of the DA in the header (for header conversion)
@@ -352,7 +351,6 @@ struct ieee80211_fast_rx {
__le16 expected_ds_bits;
u8 icv_len;
u8 key:1,
- sta_notify:1,
internal_forward:1,
uses_rss:1;
u8 da_offs, sa_offs;
--- a/net/mac80211/status.c
+++ b/net/mac80211/status.c
@@ -1227,9 +1227,6 @@ void ieee80211_tx_status_8023(struct iee
sta->status_stats.retry_count += retry_count;
if (ieee80211_hw_check(hw, REPORTS_TX_ACK_STATUS)) {
- if (acked && vif->type == NL80211_IFTYPE_STATION)
- ieee80211_sta_reset_conn_monitor(sdata);
-
sta->status_stats.last_ack = jiffies;
if (info->flags & IEEE80211_TX_STAT_ACK) {
if (sta->status_stats.lost_packets)

View File

@ -0,0 +1,227 @@
From: Felix Fietkau <nbd@nbd.name>
Date: Mon, 17 Aug 2020 13:35:32 +0200
Subject: [PATCH] mac80211: swap NEED_TXPROCESSING and HW_80211_ENCAP tx
flags
In order to unify the tx status path, the hw 802.11 encapsulation flag
needs to survive the trip to the tx status call.
Since we don't have any free bits in info->flags, we need to move one.
IEEE80211_TX_INTFL_NEED_TXPROCESSING is only used internally in mac80211,
and only before the call into the driver.
Signed-off-by: Felix Fietkau <nbd@nbd.name>
---
--- a/drivers/net/wireless/ath/ath11k/dp_tx.c
+++ b/drivers/net/wireless/ath/ath11k/dp_tx.c
@@ -14,7 +14,7 @@ ath11k_dp_tx_get_encap_type(struct ath11
{
struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
- if (tx_info->control.flags & IEEE80211_TX_CTRL_HW_80211_ENCAP)
+ if (tx_info->flags & IEEE80211_TX_CTL_HW_80211_ENCAP)
return HAL_TCL_ENCAP_TYPE_ETHERNET;
return HAL_TCL_ENCAP_TYPE_NATIVE_WIFI;
@@ -93,7 +93,7 @@ int ath11k_dp_tx(struct ath11k *ar, stru
if (test_bit(ATH11K_FLAG_CRASH_FLUSH, &ar->ab->dev_flags))
return -ESHUTDOWN;
- if (!(info->control.flags & IEEE80211_TX_CTRL_HW_80211_ENCAP) &&
+ if (!(info->flags & IEEE80211_TX_CTL_HW_80211_ENCAP) &&
!ieee80211_is_data(hdr->frame_control))
return -ENOTSUPP;
--- a/drivers/net/wireless/ath/ath11k/mac.c
+++ b/drivers/net/wireless/ath/ath11k/mac.c
@@ -3749,7 +3749,7 @@ static int ath11k_mac_mgmt_tx_wmi(struct
return -ENOSPC;
info = IEEE80211_SKB_CB(skb);
- if (!(info->control.flags & IEEE80211_TX_CTRL_HW_80211_ENCAP)) {
+ if (!(info->flags & IEEE80211_TX_CTL_HW_80211_ENCAP)) {
if ((ieee80211_is_action(hdr->frame_control) ||
ieee80211_is_deauth(hdr->frame_control) ||
ieee80211_is_disassoc(hdr->frame_control)) &&
@@ -3876,7 +3876,7 @@ static void ath11k_mac_op_tx(struct ieee
bool is_prb_rsp;
int ret;
- if (info->control.flags & IEEE80211_TX_CTRL_HW_80211_ENCAP) {
+ if (info->flags & IEEE80211_TX_CTL_HW_80211_ENCAP) {
skb_cb->flags |= ATH11K_SKB_HW_80211_ENCAP;
} else if (ieee80211_is_mgmt(hdr->frame_control)) {
is_prb_rsp = ieee80211_is_probe_resp(hdr->frame_control);
--- a/include/net/mac80211.h
+++ b/include/net/mac80211.h
@@ -720,9 +720,8 @@ struct ieee80211_bss_conf {
* @IEEE80211_TX_INTFL_OFFCHAN_TX_OK: Internal to mac80211. Used to indicate
* that a frame can be transmitted while the queues are stopped for
* off-channel operation.
- * @IEEE80211_TX_INTFL_NEED_TXPROCESSING: completely internal to mac80211,
- * used to indicate that a pending frame requires TX processing before
- * it can be sent out.
+ * @IEEE80211_TX_CTL_HW_80211_ENCAP: This frame uses hardware encapsulation
+ * (header conversion)
* @IEEE80211_TX_INTFL_RETRIED: completely internal to mac80211,
* used to indicate that a frame was already retried due to PS
* @IEEE80211_TX_INTFL_DONT_ENCRYPT: completely internal to mac80211,
@@ -791,7 +790,7 @@ enum mac80211_tx_info_flags {
IEEE80211_TX_STAT_AMPDU_NO_BACK = BIT(11),
IEEE80211_TX_CTL_RATE_CTRL_PROBE = BIT(12),
IEEE80211_TX_INTFL_OFFCHAN_TX_OK = BIT(13),
- IEEE80211_TX_INTFL_NEED_TXPROCESSING = BIT(14),
+ IEEE80211_TX_CTL_HW_80211_ENCAP = BIT(14),
IEEE80211_TX_INTFL_RETRIED = BIT(15),
IEEE80211_TX_INTFL_DONT_ENCRYPT = BIT(16),
IEEE80211_TX_CTL_NO_PS_BUFFER = BIT(17),
@@ -823,8 +822,9 @@ enum mac80211_tx_info_flags {
* @IEEE80211_TX_CTRL_AMSDU: This frame is an A-MSDU frame
* @IEEE80211_TX_CTRL_FAST_XMIT: This frame is going through the fast_xmit path
* @IEEE80211_TX_CTRL_SKIP_MPATH_LOOKUP: This frame skips mesh path lookup
- * @IEEE80211_TX_CTRL_HW_80211_ENCAP: This frame uses hardware encapsulation
- * (header conversion)
+ * @IEEE80211_TX_INTCFL_NEED_TXPROCESSING: completely internal to mac80211,
+ * used to indicate that a pending frame requires TX processing before
+ * it can be sent out.
*
* These flags are used in tx_info->control.flags.
*/
@@ -835,7 +835,7 @@ enum mac80211_tx_control_flags {
IEEE80211_TX_CTRL_AMSDU = BIT(3),
IEEE80211_TX_CTRL_FAST_XMIT = BIT(4),
IEEE80211_TX_CTRL_SKIP_MPATH_LOOKUP = BIT(5),
- IEEE80211_TX_CTRL_HW_80211_ENCAP = BIT(6),
+ IEEE80211_TX_INTCFL_NEED_TXPROCESSING = BIT(6),
};
/*
--- a/net/mac80211/mesh_hwmp.c
+++ b/net/mac80211/mesh_hwmp.c
@@ -212,7 +212,7 @@ static void prepare_frame_for_deferred_t
skb->priority = 7;
info->control.vif = &sdata->vif;
- info->flags |= IEEE80211_TX_INTFL_NEED_TXPROCESSING;
+ info->control.flags |= IEEE80211_TX_INTCFL_NEED_TXPROCESSING;
ieee80211_set_qos_hdr(sdata, skb);
ieee80211_mps_set_frame_flags(sdata, NULL, hdr);
}
@@ -1163,7 +1163,7 @@ int mesh_nexthop_resolve(struct ieee8021
if (skb_queue_len(&mpath->frame_queue) >= MESH_FRAME_QUEUE_LEN)
skb_to_free = skb_dequeue(&mpath->frame_queue);
- info->flags |= IEEE80211_TX_INTFL_NEED_TXPROCESSING;
+ info->control.flags |= IEEE80211_TX_INTCFL_NEED_TXPROCESSING;
ieee80211_set_qos_hdr(sdata, skb);
skb_queue_tail(&mpath->frame_queue, skb);
if (skb_to_free)
--- a/net/mac80211/mesh_ps.c
+++ b/net/mac80211/mesh_ps.c
@@ -432,7 +432,7 @@ static void mpsp_qos_null_append(struct
info = IEEE80211_SKB_CB(new_skb);
info->control.vif = &sdata->vif;
- info->flags |= IEEE80211_TX_INTFL_NEED_TXPROCESSING;
+ info->control.flags |= IEEE80211_TX_INTCFL_NEED_TXPROCESSING;
__skb_queue_tail(frames, new_skb);
}
--- a/net/mac80211/rx.c
+++ b/net/mac80211/rx.c
@@ -2896,7 +2896,7 @@ ieee80211_rx_h_mesh_fwding(struct ieee80
fwd_hdr->frame_control &= ~cpu_to_le16(IEEE80211_FCTL_RETRY);
info = IEEE80211_SKB_CB(fwd_skb);
memset(info, 0, sizeof(*info));
- info->flags |= IEEE80211_TX_INTFL_NEED_TXPROCESSING;
+ info->control.flags |= IEEE80211_TX_INTCFL_NEED_TXPROCESSING;
info->control.vif = &rx->sdata->vif;
info->control.jiffies = jiffies;
if (is_multicast_ether_addr(fwd_hdr->addr1)) {
--- a/net/mac80211/status.c
+++ b/net/mac80211/status.c
@@ -66,8 +66,8 @@ static void ieee80211_handle_filtered_fr
info->control.jiffies = jiffies;
info->control.vif = &sta->sdata->vif;
- info->flags |= IEEE80211_TX_INTFL_NEED_TXPROCESSING |
- IEEE80211_TX_INTFL_RETRANSMISSION;
+ info->control.flags |= IEEE80211_TX_INTCFL_NEED_TXPROCESSING;
+ info->flags |= IEEE80211_TX_INTFL_RETRANSMISSION;
info->flags &= ~IEEE80211_TX_TEMPORARY_FLAGS;
sta->status_stats.filtered++;
--- a/net/mac80211/tx.c
+++ b/net/mac80211/tx.c
@@ -530,7 +530,7 @@ ieee80211_tx_h_unicast_ps_buf(struct iee
info->control.jiffies = jiffies;
info->control.vif = &tx->sdata->vif;
- info->flags |= IEEE80211_TX_INTFL_NEED_TXPROCESSING;
+ info->control.flags |= IEEE80211_TX_INTCFL_NEED_TXPROCESSING;
info->flags &= ~IEEE80211_TX_TEMPORARY_FLAGS;
skb_queue_tail(&sta->ps_tx_buf[ac], tx->skb);
spin_unlock(&sta->ps_lock);
@@ -1132,7 +1132,7 @@ static bool ieee80211_tx_prep_agg(struct
tx->sta->sta.addr, tx->sta->sta.aid);
}
info->control.vif = &tx->sdata->vif;
- info->flags |= IEEE80211_TX_INTFL_NEED_TXPROCESSING;
+ info->control.flags |= IEEE80211_TX_INTCFL_NEED_TXPROCESSING;
info->flags &= ~IEEE80211_TX_TEMPORARY_FLAGS;
__skb_queue_tail(&tid_tx->pending, skb);
if (skb_queue_len(&tid_tx->pending) > STA_MAX_TX_BUFFER)
@@ -1177,7 +1177,7 @@ ieee80211_tx_prepare(struct ieee80211_su
* we are doing the needed processing, so remove the flag
* now.
*/
- info->flags &= ~IEEE80211_TX_INTFL_NEED_TXPROCESSING;
+ info->control.flags &= ~IEEE80211_TX_INTCFL_NEED_TXPROCESSING;
hdr = (struct ieee80211_hdr *) skb->data;
@@ -1256,7 +1256,7 @@ static struct txq_info *ieee80211_get_tx
(info->control.flags & IEEE80211_TX_CTRL_PS_RESPONSE))
return NULL;
- if (!(info->control.flags & IEEE80211_TX_CTRL_HW_80211_ENCAP) &&
+ if (!(info->flags & IEEE80211_TX_CTL_HW_80211_ENCAP) &&
unlikely(!ieee80211_is_data_present(hdr->frame_control))) {
if ((!ieee80211_is_mgmt(hdr->frame_control) ||
ieee80211_is_bufferable_mmpdu(hdr->frame_control) ||
@@ -3640,7 +3640,7 @@ begin:
else
info->flags &= ~IEEE80211_TX_CTL_AMPDU;
- if (info->control.flags & IEEE80211_TX_CTRL_HW_80211_ENCAP)
+ if (info->flags & IEEE80211_TX_CTL_HW_80211_ENCAP)
goto encap_out;
if (info->control.flags & IEEE80211_TX_CTRL_FAST_XMIT) {
@@ -4253,7 +4253,7 @@ static void ieee80211_8023_xmit(struct i
sdata = container_of(sdata->bss,
struct ieee80211_sub_if_data, u.ap);
- info->control.flags |= IEEE80211_TX_CTRL_HW_80211_ENCAP;
+ info->flags |= IEEE80211_TX_CTL_HW_80211_ENCAP;
info->control.vif = &sdata->vif;
ieee80211_tx_8023(sdata, skb, skb->len, sta, false);
@@ -4357,7 +4357,7 @@ static bool ieee80211_tx_pending_skb(str
sdata = vif_to_sdata(info->control.vif);
- if (info->flags & IEEE80211_TX_INTFL_NEED_TXPROCESSING) {
+ if (info->control.flags & IEEE80211_TX_INTCFL_NEED_TXPROCESSING) {
chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf);
if (unlikely(!chanctx_conf)) {
dev_kfree_skb(skb);
@@ -4365,7 +4365,7 @@ static bool ieee80211_tx_pending_skb(str
}
info->band = chanctx_conf->def.chan->band;
result = ieee80211_tx(sdata, NULL, skb, true, 0);
- } else if (info->control.flags & IEEE80211_TX_CTRL_HW_80211_ENCAP) {
+ } else if (info->flags & IEEE80211_TX_CTL_HW_80211_ENCAP) {
if (ieee80211_lookup_ra_sta(sdata, skb, &sta)) {
dev_kfree_skb(skb);
return true;

View File

@ -0,0 +1,159 @@
From: Felix Fietkau <nbd@nbd.name>
Date: Mon, 17 Aug 2020 13:54:19 +0200
Subject: [PATCH] mac80211: unify 802.3 (offload) and 802.11 tx status
codepath
Make ieee80211_tx_status_8023 call ieee80211_tx_status_ext, similar to
ieee80211_tx_status.
Signed-off-by: Felix Fietkau <nbd@nbd.name>
---
--- a/net/mac80211/status.c
+++ b/net/mac80211/status.c
@@ -903,7 +903,6 @@ static void __ieee80211_tx_status(struct
struct ieee80211_bar *bar;
int shift = 0;
int tid = IEEE80211_NUM_TIDS;
- u16 tx_time_est;
sband = local->hw.wiphy->bands[info->band];
fc = hdr->frame_control;
@@ -996,17 +995,6 @@ static void __ieee80211_tx_status(struct
ieee80211_hw_check(&local->hw, REPORTS_TX_ACK_STATUS))
ieee80211_sta_tx_notify(sta->sdata, (void *) skb->data,
acked, info->status.tx_time);
-
- 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);
- }
}
/* SNMP counters
@@ -1102,9 +1090,11 @@ void ieee80211_tx_status_ext(struct ieee
struct ieee80211_tx_info *info = status->info;
struct ieee80211_sta *pubsta = status->sta;
struct ieee80211_supported_band *sband;
- struct sta_info *sta;
+ struct sk_buff *skb = status->skb;
+ struct sta_info *sta = NULL;
int rates_idx, retry_count;
bool acked, noack_success;
+ u16 tx_time_est;
if (pubsta) {
sta = container_of(pubsta, struct sta_info, sta);
@@ -1156,7 +1146,18 @@ void ieee80211_tx_status_ext(struct ieee
ieee80211s_update_metric(local, sta, status);
}
- if (status->skb)
+ if (skb && (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 (skb && !(info->flags & IEEE80211_TX_CTL_HW_80211_ENCAP))
return __ieee80211_tx_status(hw, status, rates_idx,
retry_count);
@@ -1171,6 +1172,12 @@ void ieee80211_tx_status_ext(struct ieee
} else {
I802_DEBUG_INC(local->dot11FailedCount);
}
+
+ if (!skb)
+ return;
+
+ ieee80211_report_used_skb(local, skb, false);
+ dev_kfree_skb(skb);
}
EXPORT_SYMBOL(ieee80211_tx_status_ext);
@@ -1197,66 +1204,23 @@ void ieee80211_tx_status_8023(struct iee
struct ieee80211_vif *vif,
struct sk_buff *skb)
{
- struct ieee80211_local *local = hw_to_local(hw);
struct ieee80211_sub_if_data *sdata;
- struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
+ struct ieee80211_tx_status status = {
+ .skb = skb,
+ .info = IEEE80211_SKB_CB(skb),
+ };
struct sta_info *sta;
- int retry_count;
- int rates_idx;
- bool acked;
sdata = vif_to_sdata(vif);
- acked = info->flags & IEEE80211_TX_STAT_ACK;
- rates_idx = ieee80211_tx_get_rates(hw, info, &retry_count);
-
rcu_read_lock();
- if (ieee80211_lookup_ra_sta(sdata, skb, &sta))
- goto counters_update;
-
- if (IS_ERR(sta))
- goto counters_update;
-
- if (!acked)
- sta->status_stats.retry_failed++;
-
- if (rates_idx != -1)
- sta->tx_stats.last_rate = info->status.rates[rates_idx];
-
- sta->status_stats.retry_count += retry_count;
-
- if (ieee80211_hw_check(hw, REPORTS_TX_ACK_STATUS)) {
- sta->status_stats.last_ack = jiffies;
- if (info->flags & IEEE80211_TX_STAT_ACK) {
- if (sta->status_stats.lost_packets)
- sta->status_stats.lost_packets = 0;
+ if (!ieee80211_lookup_ra_sta(sdata, skb, &sta) && !IS_ERR(sta))
+ status.sta = &sta->sta;
- sta->status_stats.last_pkt_time = jiffies;
- } else {
- ieee80211_lost_packet(sta, info);
- }
- }
+ ieee80211_tx_status_ext(hw, &status);
-counters_update:
rcu_read_unlock();
- ieee80211_led_tx(local);
-
- if (!(info->flags & IEEE80211_TX_STAT_ACK) &&
- !(info->flags & IEEE80211_TX_STAT_NOACK_TRANSMITTED))
- goto skip_stats_update;
-
- I802_DEBUG_INC(local->dot11TransmittedFrameCount);
- if (is_multicast_ether_addr(skb->data))
- I802_DEBUG_INC(local->dot11MulticastTransmittedFrameCount);
- if (retry_count > 0)
- I802_DEBUG_INC(local->dot11RetryCount);
- if (retry_count > 1)
- I802_DEBUG_INC(local->dot11MultipleRetryCount);
-
-skip_stats_update:
- ieee80211_report_used_skb(local, skb, false);
- dev_kfree_skb(skb);
}
EXPORT_SYMBOL(ieee80211_tx_status_8023);

View File

@ -0,0 +1,25 @@
From: Felix Fietkau <nbd@nbd.name>
Date: Mon, 17 Aug 2020 13:55:56 +0200
Subject: [PATCH] mac80211: add missing queue/hash initialization to 802.3
xmit
Fixes AQL for encap-offloaded tx
Signed-off-by: Felix Fietkau <nbd@nbd.name>
---
--- a/net/mac80211/tx.c
+++ b/net/mac80211/tx.c
@@ -4206,6 +4206,12 @@ static void ieee80211_8023_xmit(struct i
if (is_zero_ether_addr(ra))
goto out_free;
+ if (local->ops->wake_tx_queue) {
+ u16 queue = __ieee80211_select_queue(sdata, sta, skb);
+ skb_set_queue_mapping(skb, queue);
+ skb_get_hash(skb);
+ }
+
multicast = is_multicast_ether_addr(ra);
if (sta)

View File

@ -0,0 +1,45 @@
From: Felix Fietkau <nbd@nbd.name>
Date: Mon, 17 Aug 2020 21:11:25 +0200
Subject: [PATCH] mac80211: check and refresh aggregation session in encap
offload tx
Update the last_tx timestamp to avoid tearing down the aggregation session
early. Fall back to the slow path if the session setup is still running
Signed-off-by: Felix Fietkau <nbd@nbd.name>
---
--- a/net/mac80211/tx.c
+++ b/net/mac80211/tx.c
@@ -4195,6 +4195,8 @@ static void ieee80211_8023_xmit(struct i
bool authorized = false;
bool multicast;
unsigned char *ra = ehdr->h_dest;
+ struct tid_ampdu_tx *tid_tx;
+ u8 tid;
if (IS_ERR(sta) || (sta && !sta->uploaded))
sta = NULL;
@@ -4232,6 +4234,22 @@ static void ieee80211_8023_xmit(struct i
memset(info, 0, sizeof(*info));
+ if (sta) {
+ tid = skb->priority & IEEE80211_QOS_CTL_TAG1D_MASK;
+ tid_tx = rcu_dereference(sta->ampdu_mlme.tid_tx[tid]);
+ if (tid_tx) {
+ if (!test_bit(HT_AGG_STATE_OPERATIONAL, &tid_tx->state)) {
+ /* fall back to non-offload slow path */
+ __ieee80211_subif_start_xmit(skb, dev, 0, 0, NULL);
+ return;
+ }
+
+ info->flags |= IEEE80211_TX_CTL_AMPDU;
+ if (tid_tx->timeout)
+ tid_tx->last_tx = jiffies;
+ }
+ }
+
if (unlikely(!multicast && skb->sk &&
skb_shinfo(skb)->tx_flags & SKBTX_WIFI_STATUS))
info->ack_frame_id = ieee80211_store_ack_skb(local, skb,

View File

@ -0,0 +1,63 @@
From: Felix Fietkau <nbd@nbd.name>
Date: Thu, 20 Aug 2020 17:27:00 +0200
Subject: [PATCH] mac80211: support using ieee80211_tx_status_ext to free
skbs without status info
For encap-offloaded packets, ieee80211_free_txskb cannot be used, since it
does not have the vif pointer.
Using ieee80211_tx_status_ext for this purpose has the advantage of being able
avoid an extra station lookup for AQL
Signed-off-by: Felix Fietkau <nbd@nbd.name>
---
--- a/net/mac80211/status.c
+++ b/net/mac80211/status.c
@@ -1103,6 +1103,21 @@ void ieee80211_tx_status_ext(struct ieee
sta->tx_stats.last_rate_info = *status->rate;
}
+ if (skb && (tx_time_est =
+ ieee80211_info_get_tx_time_est(IEEE80211_SKB_CB(skb))) > 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(IEEE80211_SKB_CB(skb), 0);
+ }
+
+ if (!status->info)
+ goto free;
+
rates_idx = ieee80211_tx_get_rates(hw, info, &retry_count);
sband = hw->wiphy->bands[info->band];
@@ -1146,17 +1161,6 @@ void ieee80211_tx_status_ext(struct ieee
ieee80211s_update_metric(local, sta, status);
}
- if (skb && (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 (skb && !(info->flags & IEEE80211_TX_CTL_HW_80211_ENCAP))
return __ieee80211_tx_status(hw, status, rates_idx,
retry_count);
@@ -1173,6 +1177,7 @@ void ieee80211_tx_status_ext(struct ieee
I802_DEBUG_INC(local->dot11FailedCount);
}
+free:
if (!skb)
return;

View File

@ -0,0 +1,53 @@
From: Felix Fietkau <nbd@nbd.name>
Date: Fri, 21 Aug 2020 05:49:07 +0200
Subject: [PATCH] mac80211: extend ieee80211_tx_status_ext to support bulk
free
Store processed skbs ready to be freed in a list so the driver bulk free them
Signed-off-by: Felix Fietkau <nbd@nbd.name>
---
--- a/include/net/mac80211.h
+++ b/include/net/mac80211.h
@@ -1092,12 +1092,14 @@ ieee80211_info_get_tx_time_est(struct ie
* @info: Basic tx status information
* @skb: Packet skb (can be NULL if not provided by the driver)
* @rate: The TX rate that was used when sending the packet
+ * @free_list: list where processed skbs are stored to be free'd by the driver
*/
struct ieee80211_tx_status {
struct ieee80211_sta *sta;
struct ieee80211_tx_info *info;
struct sk_buff *skb;
struct rate_info *rate;
+ struct list_head *free_list;
};
/**
--- a/net/mac80211/status.c
+++ b/net/mac80211/status.c
@@ -1053,7 +1053,10 @@ static void __ieee80211_tx_status(struct
* with this test...
*/
if (!local->monitors && (!send_to_cooked || !local->cooked_mntrs)) {
- dev_kfree_skb(skb);
+ if (status->free_list)
+ list_add_tail(&skb->list, status->free_list);
+ else
+ dev_kfree_skb(skb);
return;
}
@@ -1182,7 +1185,10 @@ free:
return;
ieee80211_report_used_skb(local, skb, false);
- dev_kfree_skb(skb);
+ if (status->free_list)
+ list_add_tail(&skb->list, status->free_list);
+ else
+ dev_kfree_skb(skb);
}
EXPORT_SYMBOL(ieee80211_tx_status_ext);

View File

@ -0,0 +1,109 @@
From: Felix Fietkau <nbd@nbd.name>
Date: Fri, 21 Aug 2020 05:51:58 +0200
Subject: [PATCH] mac80211: notify the driver when a sta uses 4-address
mode
This is needed for encapsulation offload of 4-address mode packets
Signed-off-by: Felix Fietkau <nbd@nbd.name>
---
--- a/include/net/mac80211.h
+++ b/include/net/mac80211.h
@@ -3840,6 +3840,8 @@ enum ieee80211_reconfig_type {
* This callback may sleep.
* @update_vif_config: Update virtual interface offload flags
* This callback may sleep.
+ * @sta_set_4addr: Called to notify the driver when a station starts/stops using
+ * 4-address mode
*/
struct ieee80211_ops {
void (*tx)(struct ieee80211_hw *hw,
@@ -4153,6 +4155,8 @@ struct ieee80211_ops {
struct ieee80211_sta *sta, u8 tids);
void (*update_vif_offload)(struct ieee80211_hw *hw,
struct ieee80211_vif *vif);
+ void (*sta_set_4addr)(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
+ struct ieee80211_sta *sta, bool enabled);
};
/**
--- a/net/mac80211/cfg.c
+++ b/net/mac80211/cfg.c
@@ -1698,6 +1698,7 @@ static int ieee80211_change_station(stru
rcu_assign_pointer(vlansdata->u.vlan.sta, sta);
__ieee80211_check_fast_rx_iface(vlansdata);
+ drv_sta_set_4addr(local, sta->sdata, &sta->sta, true);
}
if (sta->sdata->vif.type == NL80211_IFTYPE_AP_VLAN &&
--- a/net/mac80211/driver-ops.h
+++ b/net/mac80211/driver-ops.h
@@ -1400,4 +1400,18 @@ static inline void drv_update_vif_offloa
trace_drv_return_void(local);
}
+static inline void drv_sta_set_4addr(struct ieee80211_local *local,
+ struct ieee80211_sub_if_data *sdata,
+ struct ieee80211_sta *sta, bool enabled)
+{
+ sdata = get_bss_sdata(sdata);
+ if (!check_sdata_in_driver(sdata))
+ return;
+
+ trace_drv_sta_set_4addr(local, sdata, sta, enabled);
+ if (local->ops->sta_set_4addr)
+ local->ops->sta_set_4addr(&local->hw, &sdata->vif, sta, enabled);
+ trace_drv_return_void(local);
+}
+
#endif /* __MAC80211_DRIVER_OPS */
--- a/net/mac80211/mlme.c
+++ b/net/mac80211/mlme.c
@@ -3518,6 +3518,9 @@ static bool ieee80211_assoc_success(stru
goto out;
}
+ if (sdata->wdev.use_4addr)
+ drv_sta_set_4addr(local, sdata, &sta->sta, true);
+
mutex_unlock(&sdata->local->sta_mtx);
/*
--- a/net/mac80211/trace.h
+++ b/net/mac80211/trace.h
@@ -2739,6 +2739,33 @@ DEFINE_EVENT(local_sdata_addr_evt, drv_u
TP_ARGS(local, sdata)
);
+TRACE_EVENT(drv_sta_set_4addr,
+ TP_PROTO(struct ieee80211_local *local,
+ struct ieee80211_sub_if_data *sdata,
+ struct ieee80211_sta *sta, bool enabled),
+
+ TP_ARGS(local, sdata, sta, enabled),
+
+ TP_STRUCT__entry(
+ LOCAL_ENTRY
+ VIF_ENTRY
+ STA_ENTRY
+ __field(bool, enabled)
+ ),
+
+ TP_fast_assign(
+ LOCAL_ASSIGN;
+ VIF_ASSIGN;
+ STA_ASSIGN;
+ __entry->enabled = enabled;
+ ),
+
+ TP_printk(
+ LOCAL_PR_FMT VIF_PR_FMT STA_PR_FMT " enabled:%d",
+ LOCAL_PR_ARG, VIF_PR_ARG, STA_PR_ARG, __entry->enabled
+ )
+);
+
#endif /* !__MAC80211_DRIVER_TRACE || TRACE_HEADER_MULTI_READ */
#undef TRACE_INCLUDE_PATH

View File

@ -0,0 +1,158 @@
From: Felix Fietkau <nbd@nbd.name>
Date: Fri, 21 Aug 2020 05:54:10 +0200
Subject: [PATCH] mac80211: skip encap offload for tx multicast/control
packets
This simplifies the checks in the encap offload tx handler and allows using
it in cases where software crypto is used for multicast packets, e.g. when
using an AP_VLAN.
Signed-off-by: Felix Fietkau <nbd@nbd.name>
---
--- a/net/mac80211/iface.c
+++ b/net/mac80211/iface.c
@@ -378,7 +378,8 @@ static bool ieee80211_set_sdata_offload_
if (key->conf.cipher == WLAN_CIPHER_SUITE_AES_CMAC ||
key->conf.cipher == WLAN_CIPHER_SUITE_BIP_GMAC_128 ||
key->conf.cipher == WLAN_CIPHER_SUITE_BIP_GMAC_256 ||
- key->conf.cipher == WLAN_CIPHER_SUITE_BIP_CMAC_256)
+ key->conf.cipher == WLAN_CIPHER_SUITE_BIP_CMAC_256 ||
+ !(key->conf.flags & IEEE80211_KEY_FLAG_PAIRWISE))
continue;
if (key->conf.cipher == WLAN_CIPHER_SUITE_TKIP ||
!(key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE))
@@ -1448,7 +1449,8 @@ static void ieee80211_set_vif_encap_ops(
if (key->conf.cipher == WLAN_CIPHER_SUITE_AES_CMAC ||
key->conf.cipher == WLAN_CIPHER_SUITE_BIP_GMAC_128 ||
key->conf.cipher == WLAN_CIPHER_SUITE_BIP_GMAC_256 ||
- key->conf.cipher == WLAN_CIPHER_SUITE_BIP_CMAC_256)
+ key->conf.cipher == WLAN_CIPHER_SUITE_BIP_CMAC_256 ||
+ !(key->conf.flags & IEEE80211_KEY_FLAG_PAIRWISE))
continue;
if (!(key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE))
enabled = false;
--- a/net/mac80211/tx.c
+++ b/net/mac80211/tx.c
@@ -4190,88 +4190,47 @@ static void ieee80211_8023_xmit(struct i
struct sk_buff *skb)
{
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
- struct ethhdr *ehdr = (struct ethhdr *)skb->data;
struct ieee80211_local *local = sdata->local;
- bool authorized = false;
- bool multicast;
- unsigned char *ra = ehdr->h_dest;
struct tid_ampdu_tx *tid_tx;
u8 tid;
- if (IS_ERR(sta) || (sta && !sta->uploaded))
- sta = NULL;
-
- if (sdata->vif.type == NL80211_IFTYPE_STATION &&
- (!sta || !test_sta_flag(sta, WLAN_STA_TDLS_PEER)))
- ra = sdata->u.mgd.bssid;
-
- if (is_zero_ether_addr(ra))
- goto out_free;
-
if (local->ops->wake_tx_queue) {
u16 queue = __ieee80211_select_queue(sdata, sta, skb);
skb_set_queue_mapping(skb, queue);
skb_get_hash(skb);
}
- multicast = is_multicast_ether_addr(ra);
-
- if (sta)
- authorized = test_sta_flag(sta, WLAN_STA_AUTHORIZED);
-
- if (!multicast && !authorized &&
- (ehdr->h_proto != sdata->control_port_protocol ||
- !ether_addr_equal(sdata->vif.addr, ehdr->h_source)))
- goto out_free;
-
- if (multicast && sdata->vif.type == NL80211_IFTYPE_AP &&
- !atomic_read(&sdata->u.ap.num_mcast_sta))
- goto out_free;
-
if (unlikely(test_bit(SCAN_SW_SCANNING, &local->scanning)) &&
test_bit(SDATA_STATE_OFFCHANNEL, &sdata->state))
goto out_free;
memset(info, 0, sizeof(*info));
- if (sta) {
- tid = skb->priority & IEEE80211_QOS_CTL_TAG1D_MASK;
- tid_tx = rcu_dereference(sta->ampdu_mlme.tid_tx[tid]);
- if (tid_tx) {
- if (!test_bit(HT_AGG_STATE_OPERATIONAL, &tid_tx->state)) {
- /* fall back to non-offload slow path */
- __ieee80211_subif_start_xmit(skb, dev, 0, 0, NULL);
- return;
- }
-
- info->flags |= IEEE80211_TX_CTL_AMPDU;
- if (tid_tx->timeout)
- tid_tx->last_tx = jiffies;
+ tid = skb->priority & IEEE80211_QOS_CTL_TAG1D_MASK;
+ tid_tx = rcu_dereference(sta->ampdu_mlme.tid_tx[tid]);
+ if (tid_tx) {
+ if (!test_bit(HT_AGG_STATE_OPERATIONAL, &tid_tx->state)) {
+ /* fall back to non-offload slow path */
+ __ieee80211_subif_start_xmit(skb, dev, 0, 0, NULL);
+ return;
}
+
+ info->flags |= IEEE80211_TX_CTL_AMPDU;
+ if (tid_tx->timeout)
+ tid_tx->last_tx = jiffies;
}
- if (unlikely(!multicast && skb->sk &&
+ if (unlikely(skb->sk &&
skb_shinfo(skb)->tx_flags & SKBTX_WIFI_STATUS))
info->ack_frame_id = ieee80211_store_ack_skb(local, skb,
&info->flags, NULL);
- if (unlikely(sdata->control_port_protocol == ehdr->h_proto)) {
- if (sdata->control_port_no_encrypt)
- info->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT;
- info->control.flags |= IEEE80211_TX_CTRL_PORT_CTRL_PROTO;
- }
-
- if (multicast)
- info->flags |= IEEE80211_TX_CTL_NO_ACK;
-
info->hw_queue = sdata->vif.hw_queue[skb_get_queue_mapping(skb)];
ieee80211_tx_stats(dev, skb->len);
- if (sta) {
- sta->tx_stats.bytes[skb_get_queue_mapping(skb)] += skb->len;
- sta->tx_stats.packets[skb_get_queue_mapping(skb)]++;
- }
+ sta->tx_stats.bytes[skb_get_queue_mapping(skb)] += skb->len;
+ sta->tx_stats.packets[skb_get_queue_mapping(skb)]++;
if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN)
sdata = container_of(sdata->bss,
@@ -4292,6 +4251,7 @@ netdev_tx_t ieee80211_subif_start_xmit_8
struct net_device *dev)
{
struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+ struct ethhdr *ehdr = (struct ethhdr *)skb->data;
struct sta_info *sta;
if (unlikely(skb->len < ETH_HLEN)) {
@@ -4303,6 +4263,10 @@ netdev_tx_t ieee80211_subif_start_xmit_8
if (ieee80211_lookup_ra_sta(sdata, skb, &sta))
kfree_skb(skb);
+ else if (unlikely(IS_ERR_OR_NULL(sta) || !sta->uploaded ||
+ !test_sta_flag(sta, WLAN_STA_AUTHORIZED) ||
+ sdata->control_port_protocol == ehdr->h_proto))
+ ieee80211_subif_start_xmit(skb, dev);
else
ieee80211_8023_xmit(sdata, dev, sta, skb);

View File

@ -0,0 +1,31 @@
From: Felix Fietkau <nbd@nbd.name>
Date: Fri, 21 Aug 2020 06:03:45 +0200
Subject: [PATCH] mac80211: set info->control.hw_key for encap offload
packets
This is needed for drivers that don't do the key lookup themselves
Signed-off-by: Felix Fietkau <nbd@nbd.name>
---
--- a/net/mac80211/tx.c
+++ b/net/mac80211/tx.c
@@ -4191,6 +4191,7 @@ static void ieee80211_8023_xmit(struct i
{
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
struct ieee80211_local *local = sdata->local;
+ struct ieee80211_key *key;
struct tid_ampdu_tx *tid_tx;
u8 tid;
@@ -4239,6 +4240,10 @@ static void ieee80211_8023_xmit(struct i
info->flags |= IEEE80211_TX_CTL_HW_80211_ENCAP;
info->control.vif = &sdata->vif;
+ key = rcu_dereference(sta->ptk[sta->ptk_idx]);
+ if (key)
+ info->control.hw_key = &key->conf;
+
ieee80211_tx_8023(sdata, skb, skb->len, sta, false);
return;

View File

@ -57,7 +57,7 @@
__NL80211_ATTR_AFTER_LAST,
--- a/net/mac80211/cfg.c
+++ b/net/mac80211/cfg.c
@@ -2610,6 +2610,19 @@ static int ieee80211_get_tx_power(struct
@@ -2615,6 +2615,19 @@ static int ieee80211_get_tx_power(struct
return 0;
}
@ -77,7 +77,7 @@
static int ieee80211_set_wds_peer(struct wiphy *wiphy, struct net_device *dev,
const u8 *addr)
{
@@ -4040,6 +4053,7 @@ const struct cfg80211_ops mac80211_confi
@@ -4045,6 +4058,7 @@ const struct cfg80211_ops mac80211_confi
.set_wiphy_params = ieee80211_set_wiphy_params,
.set_tx_power = ieee80211_set_tx_power,
.get_tx_power = ieee80211_get_tx_power,
@ -87,7 +87,7 @@
CFG80211_TESTMODE_CMD(ieee80211_testmode_cmd)
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -1385,6 +1385,7 @@ struct ieee80211_local {
@@ -1383,6 +1383,7 @@ struct ieee80211_local {
int dynamic_ps_forced_timeout;
int user_power_level; /* in dBm, for all interfaces */

View File

@ -8,7 +8,7 @@
include $(TOPDIR)/rules.mk
PKG_NAME:=curl
PKG_VERSION:=7.71.1
PKG_VERSION:=7.72.0
PKG_RELEASE:=1
PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.xz
@ -16,7 +16,7 @@ PKG_SOURCE_URL:=https://dl.uxnr.de/mirror/curl/ \
https://curl.mirror.anstey.ca/ \
https://curl.askapache.com/download/ \
https://curl.haxx.se/download/
PKG_HASH:=40f83eda27cdbeb25cd4da48cefb639af1b9395d6026d2da1825bf059239658c
PKG_HASH:=0ded0808c4d85f2ee0db86980ae610cc9d165e9ca9da466196cc73c346513713
PKG_LICENSE:=MIT
PKG_LICENSE_FILES:=COPYING

View File

@ -25,7 +25,7 @@
leds {
label = "LED control button";
linux,code = <BTN_0>;
linux,code = <KEY_LIGHTS_TOGGLE>;
gpios = <&gpio 6 GPIO_ACTIVE_LOW>;
debounce-interval = <60>;
};
@ -70,6 +70,16 @@
linux,default-trigger = "phy0tpt";
};
};
gpio-export {
compatible = "gpio-export";
led_control {
gpio-export,name = "tp-link:led:control";
gpio-export,output = <0>;
gpios = <&gpio 14 GPIO_ACTIVE_LOW>;
};
};
};
&spi {

View File

@ -6,15 +6,6 @@
aliases {
label-mac-device = &eth0;
};
gpio-export {
compatible = "gpio-export";
led_control {
gpio-export,name = "tp-link:led:control";
gpios = <&gpio 14 GPIO_ACTIVE_HIGH>;
};
};
};
&partitions {

View File

@ -0,0 +1,129 @@
From: Thomas Gleixner <tglx@linutronix.de>
Date: Fri, 24 Jul 2020 22:44:41 +0200
Subject: [PATCH] genirq/affinity: Make affinity setting if activated opt-in
commit f0c7baca180046824e07fc5f1326e83a8fd150c7 upstream.
John reported that on a RK3288 system the perf per CPU interrupts are all
affine to CPU0 and provided the analysis:
"It looks like what happens is that because the interrupts are not per-CPU
in the hardware, armpmu_request_irq() calls irq_force_affinity() while
the interrupt is deactivated and then request_irq() with IRQF_PERCPU |
IRQF_NOBALANCING.
Now when irq_startup() runs with IRQ_STARTUP_NORMAL, it calls
irq_setup_affinity() which returns early because IRQF_PERCPU and
IRQF_NOBALANCING are set, leaving the interrupt on its original CPU."
This was broken by the recent commit which blocked interrupt affinity
setting in hardware before activation of the interrupt. While this works in
general, it does not work for this particular case. As contrary to the
initial analysis not all interrupt chip drivers implement an activate
callback, the safe cure is to make the deferred interrupt affinity setting
at activation time opt-in.
Implement the necessary core logic and make the two irqchip implementations
for which this is required opt-in. In hindsight this would have been the
right thing to do, but ...
Fixes: baedb87d1b53 ("genirq/affinity: Handle affinity setting on inactive interrupts correctly")
Reported-by: John Keeping <john@metanate.com>
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Tested-by: Marc Zyngier <maz@kernel.org>
Acked-by: Marc Zyngier <maz@kernel.org>
Cc: stable@vger.kernel.org
Link: https://lkml.kernel.org/r/87blk4tzgm.fsf@nanos.tec.linutronix.de
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
---
--- a/arch/x86/kernel/apic/vector.c
+++ b/arch/x86/kernel/apic/vector.c
@@ -554,6 +554,10 @@ static int x86_vector_alloc_irqs(struct
irqd->chip_data = apicd;
irqd->hwirq = virq + i;
irqd_set_single_target(irqd);
+
+ /* Don't invoke affinity setter on deactivated interrupts */
+ irqd_set_affinity_on_activate(irqd);
+
/*
* Legacy vectors are already assigned when the IOAPIC
* takes them over. They stay on the same vector. This is
--- a/drivers/irqchip/irq-gic-v3-its.c
+++ b/drivers/irqchip/irq-gic-v3-its.c
@@ -2581,6 +2581,7 @@ static int its_irq_domain_alloc(struct i
msi_alloc_info_t *info = args;
struct its_device *its_dev = info->scratchpad[0].ptr;
struct its_node *its = its_dev->its;
+ struct irq_data *irqd;
irq_hw_number_t hwirq;
int err;
int i;
@@ -2600,7 +2601,9 @@ static int its_irq_domain_alloc(struct i
irq_domain_set_hwirq_and_chip(domain, virq + i,
hwirq + i, &its_irq_chip, its_dev);
- irqd_set_single_target(irq_desc_get_irq_data(irq_to_desc(virq + i)));
+ irqd = irq_get_irq_data(virq + i);
+ irqd_set_single_target(irqd);
+ irqd_set_affinity_on_activate(irqd);
pr_debug("ID:%d pID:%d vID:%d\n",
(int)(hwirq + i - its_dev->event_map.lpi_base),
(int)(hwirq + i), virq + i);
--- a/include/linux/irq.h
+++ b/include/linux/irq.h
@@ -211,6 +211,8 @@ struct irq_data {
* IRQD_CAN_RESERVE - Can use reservation mode
* IRQD_MSI_NOMASK_QUIRK - Non-maskable MSI quirk for affinity change
* required
+ * IRQD_AFFINITY_ON_ACTIVATE - Affinity is set on activation. Don't call
+ * irq_chip::irq_set_affinity() when deactivated.
*/
enum {
IRQD_TRIGGER_MASK = 0xf,
@@ -234,6 +236,7 @@ enum {
IRQD_DEFAULT_TRIGGER_SET = (1 << 25),
IRQD_CAN_RESERVE = (1 << 26),
IRQD_MSI_NOMASK_QUIRK = (1 << 27),
+ IRQD_AFFINITY_ON_ACTIVATE = (1 << 29),
};
#define __irqd_to_state(d) ACCESS_PRIVATE((d)->common, state_use_accessors)
@@ -408,6 +411,16 @@ static inline bool irqd_msi_nomask_quirk
return __irqd_to_state(d) & IRQD_MSI_NOMASK_QUIRK;
}
+static inline void irqd_set_affinity_on_activate(struct irq_data *d)
+{
+ __irqd_to_state(d) |= IRQD_AFFINITY_ON_ACTIVATE;
+}
+
+static inline bool irqd_affinity_on_activate(struct irq_data *d)
+{
+ return __irqd_to_state(d) & IRQD_AFFINITY_ON_ACTIVATE;
+}
+
#undef __irqd_to_state
static inline irq_hw_number_t irqd_to_hwirq(struct irq_data *d)
--- a/kernel/irq/manage.c
+++ b/kernel/irq/manage.c
@@ -281,12 +281,16 @@ static bool irq_set_affinity_deactivated
struct irq_desc *desc = irq_data_to_desc(data);
/*
+ * Handle irq chips which can handle affinity only in activated
+ * state correctly
+ *
* If the interrupt is not yet activated, just store the affinity
* mask and do not call the chip driver at all. On activation the
* driver has to make sure anyway that the interrupt is in a
* useable state so startup works.
*/
- if (!IS_ENABLED(CONFIG_IRQ_DOMAIN_HIERARCHY) || irqd_is_activated(data))
+ if (!IS_ENABLED(CONFIG_IRQ_DOMAIN_HIERARCHY) ||
+ irqd_is_activated(data) || !irqd_affinity_on_activate(data))
return false;
cpumask_copy(desc->irq_common_data.affinity, mask);

View File

@ -15,7 +15,7 @@ Signed-off-by: Felix Fietkau <nbd@nbd.name>
--- a/include/linux/netdevice.h
+++ b/include/linux/netdevice.h
@@ -1412,6 +1412,7 @@ enum netdev_priv_flags {
@@ -1415,6 +1415,7 @@ enum netdev_priv_flags {
IFF_PHONY_HEADROOM = 1<<26,
IFF_MACSEC = 1<<27,
IFF_L3MDEV_RX_HANDLER = 1<<28,
@ -23,7 +23,7 @@ Signed-off-by: Felix Fietkau <nbd@nbd.name>
};
#define IFF_802_1Q_VLAN IFF_802_1Q_VLAN
@@ -1442,6 +1443,7 @@ enum netdev_priv_flags {
@@ -1445,6 +1446,7 @@ enum netdev_priv_flags {
#define IFF_RXFH_CONFIGURED IFF_RXFH_CONFIGURED
#define IFF_MACSEC IFF_MACSEC
#define IFF_L3MDEV_RX_HANDLER IFF_L3MDEV_RX_HANDLER
@ -31,7 +31,7 @@ Signed-off-by: Felix Fietkau <nbd@nbd.name>
/**
* struct net_device - The DEVICE structure.
@@ -1728,6 +1730,11 @@ struct net_device {
@@ -1731,6 +1733,11 @@ struct net_device {
const struct xfrmdev_ops *xfrmdev_ops;
#endif
@ -43,7 +43,7 @@ Signed-off-by: Felix Fietkau <nbd@nbd.name>
const struct header_ops *header_ops;
unsigned int flags;
@@ -1802,6 +1809,10 @@ struct net_device {
@@ -1805,6 +1812,10 @@ struct net_device {
struct mpls_dev __rcu *mpls_ptr;
#endif
@ -101,7 +101,7 @@ Signed-off-by: Felix Fietkau <nbd@nbd.name>
help
--- a/net/core/dev.c
+++ b/net/core/dev.c
@@ -3000,10 +3000,20 @@ static int xmit_one(struct sk_buff *skb,
@@ -3001,10 +3001,20 @@ static int xmit_one(struct sk_buff *skb,
if (!list_empty(&ptype_all) || !list_empty(&dev->ptype_all))
dev_queue_xmit_nit(skb, dev);

View File

@ -15,7 +15,7 @@ Signed-off-by: Felix Fietkau <nbd@nbd.name>
--- a/include/linux/netdevice.h
+++ b/include/linux/netdevice.h
@@ -1514,6 +1514,7 @@ enum netdev_priv_flags {
@@ -1517,6 +1517,7 @@ enum netdev_priv_flags {
IFF_FAILOVER_SLAVE = 1<<28,
IFF_L3MDEV_RX_HANDLER = 1<<29,
IFF_LIVE_RENAME_OK = 1<<30,
@ -23,7 +23,7 @@ Signed-off-by: Felix Fietkau <nbd@nbd.name>
};
#define IFF_802_1Q_VLAN IFF_802_1Q_VLAN
@@ -1546,6 +1547,7 @@ enum netdev_priv_flags {
@@ -1549,6 +1550,7 @@ enum netdev_priv_flags {
#define IFF_FAILOVER_SLAVE IFF_FAILOVER_SLAVE
#define IFF_L3MDEV_RX_HANDLER IFF_L3MDEV_RX_HANDLER
#define IFF_LIVE_RENAME_OK IFF_LIVE_RENAME_OK
@ -31,7 +31,7 @@ Signed-off-by: Felix Fietkau <nbd@nbd.name>
/**
* struct net_device - The DEVICE structure.
@@ -1846,6 +1848,11 @@ struct net_device {
@@ -1849,6 +1851,11 @@ struct net_device {
const struct tlsdev_ops *tlsdev_ops;
#endif
@ -43,7 +43,7 @@ Signed-off-by: Felix Fietkau <nbd@nbd.name>
const struct header_ops *header_ops;
unsigned int flags;
@@ -1928,6 +1935,10 @@ struct net_device {
@@ -1931,6 +1938,10 @@ struct net_device {
struct mpls_dev __rcu *mpls_ptr;
#endif
@ -101,7 +101,7 @@ Signed-off-by: Felix Fietkau <nbd@nbd.name>
help
--- a/net/core/dev.c
+++ b/net/core/dev.c
@@ -3251,10 +3251,20 @@ static int xmit_one(struct sk_buff *skb,
@@ -3252,10 +3252,20 @@ static int xmit_one(struct sk_buff *skb,
if (!list_empty(&ptype_all) || !list_empty(&dev->ptype_all))
dev_queue_xmit_nit(skb, dev);

View File

@ -15,7 +15,7 @@ Signed-off-by: Felix Fietkau <nbd@nbd.name>
--- a/include/linux/netdevice.h
+++ b/include/linux/netdevice.h
@@ -1546,6 +1546,7 @@ enum netdev_priv_flags {
@@ -1549,6 +1549,7 @@ enum netdev_priv_flags {
IFF_FAILOVER_SLAVE = 1<<28,
IFF_L3MDEV_RX_HANDLER = 1<<29,
IFF_LIVE_RENAME_OK = 1<<30,
@ -23,7 +23,7 @@ Signed-off-by: Felix Fietkau <nbd@nbd.name>
};
#define IFF_802_1Q_VLAN IFF_802_1Q_VLAN
@@ -1578,6 +1579,7 @@ enum netdev_priv_flags {
@@ -1581,6 +1582,7 @@ enum netdev_priv_flags {
#define IFF_FAILOVER_SLAVE IFF_FAILOVER_SLAVE
#define IFF_L3MDEV_RX_HANDLER IFF_L3MDEV_RX_HANDLER
#define IFF_LIVE_RENAME_OK IFF_LIVE_RENAME_OK
@ -31,7 +31,7 @@ Signed-off-by: Felix Fietkau <nbd@nbd.name>
/**
* struct net_device - The DEVICE structure.
@@ -1879,6 +1881,11 @@ struct net_device {
@@ -1882,6 +1884,11 @@ struct net_device {
const struct tlsdev_ops *tlsdev_ops;
#endif
@ -43,7 +43,7 @@ Signed-off-by: Felix Fietkau <nbd@nbd.name>
const struct header_ops *header_ops;
unsigned int flags;
@@ -1961,6 +1968,10 @@ struct net_device {
@@ -1964,6 +1971,10 @@ struct net_device {
struct mpls_dev __rcu *mpls_ptr;
#endif
@ -101,7 +101,7 @@ Signed-off-by: Felix Fietkau <nbd@nbd.name>
help
--- a/net/core/dev.c
+++ b/net/core/dev.c
@@ -3191,10 +3191,20 @@ static int xmit_one(struct sk_buff *skb,
@@ -3192,10 +3192,20 @@ static int xmit_one(struct sk_buff *skb,
if (dev_nit_active(dev))
dev_queue_xmit_nit(skb, dev);

View File

@ -0,0 +1,339 @@
From: Felix Fietkau <nbd@nbd.name>
Date: Sun, 26 Jul 2020 14:03:21 +0200
Subject: [PATCH] net: add support for threaded NAPI polling
For some drivers (especially 802.11 drivers), doing a lot of work in the NAPI
poll function does not perform well. Since NAPI poll is bound to the CPU it
was scheduled from, we can easily end up with a few very busy CPUs spending
most of their time in softirq/ksoftirqd and some idle ones.
Introduce threaded NAPI for such drivers based on a workqueue. The API is the
same except for using netif_threaded_napi_add instead of netif_napi_add.
In my tests with mt76 on MT7621 using threaded NAPI + a thread for tx scheduling
improves LAN->WLAN bridging throughput by 10-50%. Throughput without threaded
NAPI is wildly inconsistent, depending on the CPU that runs the tx scheduling
thread.
With threaded NAPI it seems stable and consistent (and higher than the best
results I got without it).
Based on a patch by Hillf Danton
Cc: Hillf Danton <hdanton@sina.com>
Signed-off-by: Felix Fietkau <nbd@nbd.name>
---
--- a/include/linux/netdevice.h
+++ b/include/linux/netdevice.h
@@ -326,6 +326,7 @@ struct napi_struct {
struct list_head dev_list;
struct hlist_node napi_hash_node;
unsigned int napi_id;
+ struct work_struct work;
};
enum {
@@ -336,6 +337,7 @@ enum {
NAPI_STATE_HASHED, /* In NAPI hash (busy polling possible) */
NAPI_STATE_NO_BUSY_POLL,/* Do not add in napi_hash, no busy polling */
NAPI_STATE_IN_BUSY_POLL,/* sk_busy_loop() owns this NAPI */
+ NAPI_STATE_THREADED, /* Use threaded NAPI */
};
enum {
@@ -346,6 +348,7 @@ enum {
NAPIF_STATE_HASHED = BIT(NAPI_STATE_HASHED),
NAPIF_STATE_NO_BUSY_POLL = BIT(NAPI_STATE_NO_BUSY_POLL),
NAPIF_STATE_IN_BUSY_POLL = BIT(NAPI_STATE_IN_BUSY_POLL),
+ NAPIF_STATE_THREADED = BIT(NAPI_STATE_THREADED),
};
enum gro_result {
@@ -2093,6 +2096,26 @@ void netif_napi_add(struct net_device *d
int (*poll)(struct napi_struct *, int), int weight);
/**
+ * netif_threaded_napi_add - initialize a NAPI context
+ * @dev: network device
+ * @napi: NAPI context
+ * @poll: polling function
+ * @weight: default weight
+ *
+ * This variant of netif_napi_add() should be used from drivers using NAPI
+ * with CPU intensive poll functions.
+ * This will schedule polling from a high priority workqueue
+ */
+static inline void netif_threaded_napi_add(struct net_device *dev,
+ struct napi_struct *napi,
+ int (*poll)(struct napi_struct *, int),
+ int weight)
+{
+ set_bit(NAPI_STATE_THREADED, &napi->state);
+ netif_napi_add(dev, napi, poll, weight);
+}
+
+/**
* netif_tx_napi_add - initialize a NAPI context
* @dev: network device
* @napi: NAPI context
--- a/net/core/dev.c
+++ b/net/core/dev.c
@@ -160,6 +160,7 @@ static DEFINE_SPINLOCK(offload_lock);
struct list_head ptype_base[PTYPE_HASH_SIZE] __read_mostly;
struct list_head ptype_all __read_mostly; /* Taps */
static struct list_head offload_base __read_mostly;
+static struct workqueue_struct *napi_workq __read_mostly;
static int netif_rx_internal(struct sk_buff *skb);
static int call_netdevice_notifiers_info(unsigned long val,
@@ -5237,6 +5238,11 @@ void __napi_schedule(struct napi_struct
{
unsigned long flags;
+ if (test_bit(NAPI_STATE_THREADED, &n->state)) {
+ queue_work(napi_workq, &n->work);
+ return;
+ }
+
local_irq_save(flags);
____napi_schedule(this_cpu_ptr(&softnet_data), n);
local_irq_restore(flags);
@@ -5284,6 +5290,11 @@ EXPORT_SYMBOL(napi_schedule_prep);
*/
void __napi_schedule_irqoff(struct napi_struct *n)
{
+ if (test_bit(NAPI_STATE_THREADED, &n->state)) {
+ queue_work(napi_workq, &n->work);
+ return;
+ }
+
____napi_schedule(this_cpu_ptr(&softnet_data), n);
}
EXPORT_SYMBOL(__napi_schedule_irqoff);
@@ -5521,6 +5532,82 @@ static enum hrtimer_restart napi_watchdo
return HRTIMER_NORESTART;
}
+static int __napi_poll(struct napi_struct *n, bool *repoll)
+{
+ int work, weight;
+
+ weight = n->weight;
+
+ /* This NAPI_STATE_SCHED test is for avoiding a race
+ * with netpoll's poll_napi(). Only the entity which
+ * obtains the lock and sees NAPI_STATE_SCHED set will
+ * actually make the ->poll() call. Therefore we avoid
+ * accidentally calling ->poll() when NAPI is not scheduled.
+ */
+ work = 0;
+ if (test_bit(NAPI_STATE_SCHED, &n->state)) {
+ work = n->poll(n, weight);
+ trace_napi_poll(n, work, weight);
+ }
+
+ WARN_ON_ONCE(work > weight);
+
+ if (likely(work < weight))
+ return work;
+
+ /* Drivers must not modify the NAPI state if they
+ * consume the entire weight. In such cases this code
+ * still "owns" the NAPI instance and therefore can
+ * move the instance around on the list at-will.
+ */
+ if (unlikely(napi_disable_pending(n))) {
+ napi_complete(n);
+ return work;
+ }
+
+ if (n->gro_list) {
+ /* flush too old packets
+ * If HZ < 1000, flush all packets.
+ */
+ napi_gro_flush(n, HZ >= 1000);
+ }
+
+ *repoll = true;
+
+ return work;
+}
+
+static void napi_workfn(struct work_struct *work)
+{
+ struct napi_struct *n = container_of(work, struct napi_struct, work);
+ void *have;
+
+ for (;;) {
+ bool repoll = false;
+
+ local_bh_disable();
+
+ have = netpoll_poll_lock(n);
+ __napi_poll(n, &repoll);
+ netpoll_poll_unlock(have);
+
+ local_bh_enable();
+
+ if (!repoll)
+ return;
+
+ if (!need_resched())
+ continue;
+
+ /*
+ * have to pay for the latency of task switch even if
+ * napi is scheduled
+ */
+ queue_work(napi_workq, work);
+ return;
+ }
+}
+
void netif_napi_add(struct net_device *dev, struct napi_struct *napi,
int (*poll)(struct napi_struct *, int), int weight)
{
@@ -5540,6 +5627,7 @@ void netif_napi_add(struct net_device *d
#ifdef CONFIG_NETPOLL
napi->poll_owner = -1;
#endif
+ INIT_WORK(&napi->work, napi_workfn);
set_bit(NAPI_STATE_SCHED, &napi->state);
napi_hash_add(napi);
}
@@ -5565,6 +5653,7 @@ EXPORT_SYMBOL(napi_disable);
void netif_napi_del(struct napi_struct *napi)
{
might_sleep();
+ cancel_work_sync(&napi->work);
if (napi_hash_del(napi))
synchronize_net();
list_del_init(&napi->dev_list);
@@ -5578,48 +5667,18 @@ EXPORT_SYMBOL(netif_napi_del);
static int napi_poll(struct napi_struct *n, struct list_head *repoll)
{
+ bool do_repoll = false;
void *have;
- int work, weight;
+ int work;
list_del_init(&n->poll_list);
have = netpoll_poll_lock(n);
- weight = n->weight;
-
- /* This NAPI_STATE_SCHED test is for avoiding a race
- * with netpoll's poll_napi(). Only the entity which
- * obtains the lock and sees NAPI_STATE_SCHED set will
- * actually make the ->poll() call. Therefore we avoid
- * accidentally calling ->poll() when NAPI is not scheduled.
- */
- work = 0;
- if (test_bit(NAPI_STATE_SCHED, &n->state)) {
- work = n->poll(n, weight);
- trace_napi_poll(n, work, weight);
- }
-
- WARN_ON_ONCE(work > weight);
-
- if (likely(work < weight))
- goto out_unlock;
+ work = __napi_poll(n, &do_repoll);
- /* Drivers must not modify the NAPI state if they
- * consume the entire weight. In such cases this code
- * still "owns" the NAPI instance and therefore can
- * move the instance around on the list at-will.
- */
- if (unlikely(napi_disable_pending(n))) {
- napi_complete(n);
+ if (!do_repoll)
goto out_unlock;
- }
-
- if (n->gro_list) {
- /* flush too old packets
- * If HZ < 1000, flush all packets.
- */
- napi_gro_flush(n, HZ >= 1000);
- }
/* Some drivers may have called napi_schedule
* prior to exhausting their budget.
@@ -8855,6 +8914,10 @@ static int __init net_dev_init(void)
sd->backlog.weight = weight_p;
}
+ napi_workq = alloc_workqueue("napi_workq", WQ_UNBOUND | WQ_HIGHPRI,
+ WQ_UNBOUND_MAX_ACTIVE | WQ_SYSFS);
+ BUG_ON(!napi_workq);
+
dev_boot_phase = 0;
/* The loopback device is special if any other network devices
--- a/net/core/net-sysfs.c
+++ b/net/core/net-sysfs.c
@@ -441,6 +441,52 @@ static ssize_t proto_down_store(struct d
}
NETDEVICE_SHOW_RW(proto_down, fmt_dec);
+static int change_napi_threaded(struct net_device *dev, unsigned long val)
+{
+ struct napi_struct *napi;
+
+ if (list_empty(&dev->napi_list))
+ return -EOPNOTSUPP;
+
+ list_for_each_entry(napi, &dev->napi_list, dev_list) {
+ if (val)
+ set_bit(NAPI_STATE_THREADED, &napi->state);
+ else
+ clear_bit(NAPI_STATE_THREADED, &napi->state);
+ }
+
+ return 0;
+}
+
+static ssize_t napi_threaded_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t len)
+{
+ return netdev_store(dev, attr, buf, len, change_napi_threaded);
+}
+
+static ssize_t napi_threaded_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct net_device *netdev = to_net_dev(dev);
+ struct napi_struct *napi;
+ bool enabled = false;
+
+ if (!rtnl_trylock())
+ return restart_syscall();
+
+ list_for_each_entry(napi, &netdev->napi_list, dev_list) {
+ if (test_bit(NAPI_STATE_THREADED, &napi->state))
+ enabled = true;
+ }
+
+ rtnl_unlock();
+
+ return sprintf(buf, fmt_dec, enabled);
+}
+static DEVICE_ATTR_RW(napi_threaded);
+
static ssize_t phys_port_id_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
@@ -536,6 +582,7 @@ static struct attribute *net_class_attrs
&dev_attr_flags.attr,
&dev_attr_tx_queue_len.attr,
&dev_attr_gro_flush_timeout.attr,
+ &dev_attr_napi_threaded.attr,
&dev_attr_phys_port_id.attr,
&dev_attr_phys_port_name.attr,
&dev_attr_phys_switch_id.attr,

View File

@ -0,0 +1,339 @@
From: Felix Fietkau <nbd@nbd.name>
Date: Sun, 26 Jul 2020 14:03:21 +0200
Subject: [PATCH] net: add support for threaded NAPI polling
For some drivers (especially 802.11 drivers), doing a lot of work in the NAPI
poll function does not perform well. Since NAPI poll is bound to the CPU it
was scheduled from, we can easily end up with a few very busy CPUs spending
most of their time in softirq/ksoftirqd and some idle ones.
Introduce threaded NAPI for such drivers based on a workqueue. The API is the
same except for using netif_threaded_napi_add instead of netif_napi_add.
In my tests with mt76 on MT7621 using threaded NAPI + a thread for tx scheduling
improves LAN->WLAN bridging throughput by 10-50%. Throughput without threaded
NAPI is wildly inconsistent, depending on the CPU that runs the tx scheduling
thread.
With threaded NAPI it seems stable and consistent (and higher than the best
results I got without it).
Based on a patch by Hillf Danton
Cc: Hillf Danton <hdanton@sina.com>
Signed-off-by: Felix Fietkau <nbd@nbd.name>
---
--- a/include/linux/netdevice.h
+++ b/include/linux/netdevice.h
@@ -339,6 +339,7 @@ struct napi_struct {
struct list_head dev_list;
struct hlist_node napi_hash_node;
unsigned int napi_id;
+ struct work_struct work;
};
enum {
@@ -349,6 +350,7 @@ enum {
NAPI_STATE_HASHED, /* In NAPI hash (busy polling possible) */
NAPI_STATE_NO_BUSY_POLL,/* Do not add in napi_hash, no busy polling */
NAPI_STATE_IN_BUSY_POLL,/* sk_busy_loop() owns this NAPI */
+ NAPI_STATE_THREADED, /* Use threaded NAPI */
};
enum {
@@ -359,6 +361,7 @@ enum {
NAPIF_STATE_HASHED = BIT(NAPI_STATE_HASHED),
NAPIF_STATE_NO_BUSY_POLL = BIT(NAPI_STATE_NO_BUSY_POLL),
NAPIF_STATE_IN_BUSY_POLL = BIT(NAPI_STATE_IN_BUSY_POLL),
+ NAPIF_STATE_THREADED = BIT(NAPI_STATE_THREADED),
};
enum gro_result {
@@ -2230,6 +2233,26 @@ void netif_napi_add(struct net_device *d
int (*poll)(struct napi_struct *, int), int weight);
/**
+ * netif_threaded_napi_add - initialize a NAPI context
+ * @dev: network device
+ * @napi: NAPI context
+ * @poll: polling function
+ * @weight: default weight
+ *
+ * This variant of netif_napi_add() should be used from drivers using NAPI
+ * with CPU intensive poll functions.
+ * This will schedule polling from a high priority workqueue
+ */
+static inline void netif_threaded_napi_add(struct net_device *dev,
+ struct napi_struct *napi,
+ int (*poll)(struct napi_struct *, int),
+ int weight)
+{
+ set_bit(NAPI_STATE_THREADED, &napi->state);
+ netif_napi_add(dev, napi, poll, weight);
+}
+
+/**
* netif_tx_napi_add - initialize a NAPI context
* @dev: network device
* @napi: NAPI context
--- a/net/core/dev.c
+++ b/net/core/dev.c
@@ -160,6 +160,7 @@ static DEFINE_SPINLOCK(offload_lock);
struct list_head ptype_base[PTYPE_HASH_SIZE] __read_mostly;
struct list_head ptype_all __read_mostly; /* Taps */
static struct list_head offload_base __read_mostly;
+static struct workqueue_struct *napi_workq __read_mostly;
static int netif_rx_internal(struct sk_buff *skb);
static int call_netdevice_notifiers_info(unsigned long val,
@@ -5891,6 +5892,11 @@ void __napi_schedule(struct napi_struct
{
unsigned long flags;
+ if (test_bit(NAPI_STATE_THREADED, &n->state)) {
+ queue_work(napi_workq, &n->work);
+ return;
+ }
+
local_irq_save(flags);
____napi_schedule(this_cpu_ptr(&softnet_data), n);
local_irq_restore(flags);
@@ -5938,6 +5944,11 @@ EXPORT_SYMBOL(napi_schedule_prep);
*/
void __napi_schedule_irqoff(struct napi_struct *n)
{
+ if (test_bit(NAPI_STATE_THREADED, &n->state)) {
+ queue_work(napi_workq, &n->work);
+ return;
+ }
+
____napi_schedule(this_cpu_ptr(&softnet_data), n);
}
EXPORT_SYMBOL(__napi_schedule_irqoff);
@@ -6186,6 +6197,82 @@ static void init_gro_hash(struct napi_st
napi->gro_bitmask = 0;
}
+static int __napi_poll(struct napi_struct *n, bool *repoll)
+{
+ int work, weight;
+
+ weight = n->weight;
+
+ /* This NAPI_STATE_SCHED test is for avoiding a race
+ * with netpoll's poll_napi(). Only the entity which
+ * obtains the lock and sees NAPI_STATE_SCHED set will
+ * actually make the ->poll() call. Therefore we avoid
+ * accidentally calling ->poll() when NAPI is not scheduled.
+ */
+ work = 0;
+ if (test_bit(NAPI_STATE_SCHED, &n->state)) {
+ work = n->poll(n, weight);
+ trace_napi_poll(n, work, weight);
+ }
+
+ WARN_ON_ONCE(work > weight);
+
+ if (likely(work < weight))
+ return work;
+
+ /* Drivers must not modify the NAPI state if they
+ * consume the entire weight. In such cases this code
+ * still "owns" the NAPI instance and therefore can
+ * move the instance around on the list at-will.
+ */
+ if (unlikely(napi_disable_pending(n))) {
+ napi_complete(n);
+ return work;
+ }
+
+ if (n->gro_bitmask) {
+ /* flush too old packets
+ * If HZ < 1000, flush all packets.
+ */
+ napi_gro_flush(n, HZ >= 1000);
+ }
+
+ *repoll = true;
+
+ return work;
+}
+
+static void napi_workfn(struct work_struct *work)
+{
+ struct napi_struct *n = container_of(work, struct napi_struct, work);
+ void *have;
+
+ for (;;) {
+ bool repoll = false;
+
+ local_bh_disable();
+
+ have = netpoll_poll_lock(n);
+ __napi_poll(n, &repoll);
+ netpoll_poll_unlock(have);
+
+ local_bh_enable();
+
+ if (!repoll)
+ return;
+
+ if (!need_resched())
+ continue;
+
+ /*
+ * have to pay for the latency of task switch even if
+ * napi is scheduled
+ */
+ queue_work(napi_workq, work);
+ return;
+ }
+}
+
void netif_napi_add(struct net_device *dev, struct napi_struct *napi,
int (*poll)(struct napi_struct *, int), int weight)
{
@@ -6204,6 +6291,7 @@ void netif_napi_add(struct net_device *d
#ifdef CONFIG_NETPOLL
napi->poll_owner = -1;
#endif
+ INIT_WORK(&napi->work, napi_workfn);
set_bit(NAPI_STATE_SCHED, &napi->state);
napi_hash_add(napi);
}
@@ -6242,6 +6330,7 @@ static void flush_gro_hash(struct napi_s
void netif_napi_del(struct napi_struct *napi)
{
might_sleep();
+ cancel_work_sync(&napi->work);
if (napi_hash_del(napi))
synchronize_net();
list_del_init(&napi->dev_list);
@@ -6254,48 +6343,18 @@ EXPORT_SYMBOL(netif_napi_del);
static int napi_poll(struct napi_struct *n, struct list_head *repoll)
{
+ bool do_repoll = false;
void *have;
- int work, weight;
+ int work;
list_del_init(&n->poll_list);
have = netpoll_poll_lock(n);
- weight = n->weight;
-
- /* This NAPI_STATE_SCHED test is for avoiding a race
- * with netpoll's poll_napi(). Only the entity which
- * obtains the lock and sees NAPI_STATE_SCHED set will
- * actually make the ->poll() call. Therefore we avoid
- * accidentally calling ->poll() when NAPI is not scheduled.
- */
- work = 0;
- if (test_bit(NAPI_STATE_SCHED, &n->state)) {
- work = n->poll(n, weight);
- trace_napi_poll(n, work, weight);
- }
-
- WARN_ON_ONCE(work > weight);
-
- if (likely(work < weight))
- goto out_unlock;
+ work = __napi_poll(n, &do_repoll);
- /* Drivers must not modify the NAPI state if they
- * consume the entire weight. In such cases this code
- * still "owns" the NAPI instance and therefore can
- * move the instance around on the list at-will.
- */
- if (unlikely(napi_disable_pending(n))) {
- napi_complete(n);
+ if (!do_repoll)
goto out_unlock;
- }
-
- if (n->gro_bitmask) {
- /* flush too old packets
- * If HZ < 1000, flush all packets.
- */
- napi_gro_flush(n, HZ >= 1000);
- }
/* Some drivers may have called napi_schedule
* prior to exhausting their budget.
@@ -9895,6 +9954,10 @@ static int __init net_dev_init(void)
sd->backlog.weight = weight_p;
}
+ napi_workq = alloc_workqueue("napi_workq", WQ_UNBOUND | WQ_HIGHPRI,
+ WQ_UNBOUND_MAX_ACTIVE | WQ_SYSFS);
+ BUG_ON(!napi_workq);
+
dev_boot_phase = 0;
/* The loopback device is special if any other network devices
--- a/net/core/net-sysfs.c
+++ b/net/core/net-sysfs.c
@@ -447,6 +447,52 @@ static ssize_t proto_down_store(struct d
}
NETDEVICE_SHOW_RW(proto_down, fmt_dec);
+static int change_napi_threaded(struct net_device *dev, unsigned long val)
+{
+ struct napi_struct *napi;
+
+ if (list_empty(&dev->napi_list))
+ return -EOPNOTSUPP;
+
+ list_for_each_entry(napi, &dev->napi_list, dev_list) {
+ if (val)
+ set_bit(NAPI_STATE_THREADED, &napi->state);
+ else
+ clear_bit(NAPI_STATE_THREADED, &napi->state);
+ }
+
+ return 0;
+}
+
+static ssize_t napi_threaded_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t len)
+{
+ return netdev_store(dev, attr, buf, len, change_napi_threaded);
+}
+
+static ssize_t napi_threaded_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct net_device *netdev = to_net_dev(dev);
+ struct napi_struct *napi;
+ bool enabled = false;
+
+ if (!rtnl_trylock())
+ return restart_syscall();
+
+ list_for_each_entry(napi, &netdev->napi_list, dev_list) {
+ if (test_bit(NAPI_STATE_THREADED, &napi->state))
+ enabled = true;
+ }
+
+ rtnl_unlock();
+
+ return sprintf(buf, fmt_dec, enabled);
+}
+static DEVICE_ATTR_RW(napi_threaded);
+
static ssize_t phys_port_id_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
@@ -542,6 +588,7 @@ static struct attribute *net_class_attrs
&dev_attr_flags.attr,
&dev_attr_tx_queue_len.attr,
&dev_attr_gro_flush_timeout.attr,
+ &dev_attr_napi_threaded.attr,
&dev_attr_phys_port_id.attr,
&dev_attr_phys_port_name.attr,
&dev_attr_phys_switch_id.attr,

View File

@ -0,0 +1,343 @@
From: Felix Fietkau <nbd@nbd.name>
Date: Sun, 26 Jul 2020 14:03:21 +0200
Subject: [PATCH] net: add support for threaded NAPI polling
For some drivers (especially 802.11 drivers), doing a lot of work in the NAPI
poll function does not perform well. Since NAPI poll is bound to the CPU it
was scheduled from, we can easily end up with a few very busy CPUs spending
most of their time in softirq/ksoftirqd and some idle ones.
Introduce threaded NAPI for such drivers based on a workqueue. The API is the
same except for using netif_threaded_napi_add instead of netif_napi_add.
In my tests with mt76 on MT7621 using threaded NAPI + a thread for tx scheduling
improves LAN->WLAN bridging throughput by 10-50%. Throughput without threaded
NAPI is wildly inconsistent, depending on the CPU that runs the tx scheduling
thread.
With threaded NAPI it seems stable and consistent (and higher than the best
results I got without it).
Based on a patch by Hillf Danton
Cc: Hillf Danton <hdanton@sina.com>
Signed-off-by: Felix Fietkau <nbd@nbd.name>
---
--- a/include/linux/netdevice.h
+++ b/include/linux/netdevice.h
@@ -340,6 +340,7 @@ struct napi_struct {
struct list_head dev_list;
struct hlist_node napi_hash_node;
unsigned int napi_id;
+ struct work_struct work;
};
enum {
@@ -350,6 +351,7 @@ enum {
NAPI_STATE_HASHED, /* In NAPI hash (busy polling possible) */
NAPI_STATE_NO_BUSY_POLL,/* Do not add in napi_hash, no busy polling */
NAPI_STATE_IN_BUSY_POLL,/* sk_busy_loop() owns this NAPI */
+ NAPI_STATE_THREADED, /* Use threaded NAPI */
};
enum {
@@ -360,6 +362,7 @@ enum {
NAPIF_STATE_HASHED = BIT(NAPI_STATE_HASHED),
NAPIF_STATE_NO_BUSY_POLL = BIT(NAPI_STATE_NO_BUSY_POLL),
NAPIF_STATE_IN_BUSY_POLL = BIT(NAPI_STATE_IN_BUSY_POLL),
+ NAPIF_STATE_THREADED = BIT(NAPI_STATE_THREADED),
};
enum gro_result {
@@ -2249,6 +2252,26 @@ void netif_napi_add(struct net_device *d
int (*poll)(struct napi_struct *, int), int weight);
/**
+ * netif_threaded_napi_add - initialize a NAPI context
+ * @dev: network device
+ * @napi: NAPI context
+ * @poll: polling function
+ * @weight: default weight
+ *
+ * This variant of netif_napi_add() should be used from drivers using NAPI
+ * with CPU intensive poll functions.
+ * This will schedule polling from a high priority workqueue
+ */
+static inline void netif_threaded_napi_add(struct net_device *dev,
+ struct napi_struct *napi,
+ int (*poll)(struct napi_struct *, int),
+ int weight)
+{
+ set_bit(NAPI_STATE_THREADED, &napi->state);
+ netif_napi_add(dev, napi, poll, weight);
+}
+
+/**
* netif_tx_napi_add - initialize a NAPI context
* @dev: network device
* @napi: NAPI context
--- a/net/core/dev.c
+++ b/net/core/dev.c
@@ -156,6 +156,7 @@ static DEFINE_SPINLOCK(offload_lock);
struct list_head ptype_base[PTYPE_HASH_SIZE] __read_mostly;
struct list_head ptype_all __read_mostly; /* Taps */
static struct list_head offload_base __read_mostly;
+static struct workqueue_struct *napi_workq __read_mostly;
static int netif_rx_internal(struct sk_buff *skb);
static int call_netdevice_notifiers_info(unsigned long val,
@@ -5910,6 +5911,11 @@ void __napi_schedule(struct napi_struct
{
unsigned long flags;
+ if (test_bit(NAPI_STATE_THREADED, &n->state)) {
+ queue_work(napi_workq, &n->work);
+ return;
+ }
+
local_irq_save(flags);
____napi_schedule(this_cpu_ptr(&softnet_data), n);
local_irq_restore(flags);
@@ -5957,6 +5963,11 @@ EXPORT_SYMBOL(napi_schedule_prep);
*/
void __napi_schedule_irqoff(struct napi_struct *n)
{
+ if (test_bit(NAPI_STATE_THREADED, &n->state)) {
+ queue_work(napi_workq, &n->work);
+ return;
+ }
+
____napi_schedule(this_cpu_ptr(&softnet_data), n);
}
EXPORT_SYMBOL(__napi_schedule_irqoff);
@@ -6218,6 +6229,84 @@ static void init_gro_hash(struct napi_st
napi->gro_bitmask = 0;
}
+static int __napi_poll(struct napi_struct *n, bool *repoll)
+{
+ int work, weight;
+
+ weight = n->weight;
+
+ /* This NAPI_STATE_SCHED test is for avoiding a race
+ * with netpoll's poll_napi(). Only the entity which
+ * obtains the lock and sees NAPI_STATE_SCHED set will
+ * actually make the ->poll() call. Therefore we avoid
+ * accidentally calling ->poll() when NAPI is not scheduled.
+ */
+ work = 0;
+ if (test_bit(NAPI_STATE_SCHED, &n->state)) {
+ work = n->poll(n, weight);
+ trace_napi_poll(n, work, weight);
+ }
+
+ WARN_ON_ONCE(work > weight);
+
+ if (likely(work < weight))
+ return work;
+
+ /* Drivers must not modify the NAPI state if they
+ * consume the entire weight. In such cases this code
+ * still "owns" the NAPI instance and therefore can
+ * move the instance around on the list at-will.
+ */
+ if (unlikely(napi_disable_pending(n))) {
+ napi_complete(n);
+ return work;
+ }
+
+ if (n->gro_bitmask) {
+ /* flush too old packets
+ * If HZ < 1000, flush all packets.
+ */
+ napi_gro_flush(n, HZ >= 1000);
+ }
+
+ gro_normal_list(n);
+
+ *repoll = true;
+
+ return work;
+}
+
+static void napi_workfn(struct work_struct *work)
+{
+ struct napi_struct *n = container_of(work, struct napi_struct, work);
+ void *have;
+
+ for (;;) {
+ bool repoll = false;
+
+ local_bh_disable();
+
+ have = netpoll_poll_lock(n);
+ __napi_poll(n, &repoll);
+ netpoll_poll_unlock(have);
+
+ local_bh_enable();
+
+ if (!repoll)
+ return;
+
+ if (!need_resched())
+ continue;
+
+ /*
+ * have to pay for the latency of task switch even if
+ * napi is scheduled
+ */
+ queue_work(napi_workq, work);
+ return;
+ }
+}
+
void netif_napi_add(struct net_device *dev, struct napi_struct *napi,
int (*poll)(struct napi_struct *, int), int weight)
{
@@ -6238,6 +6327,7 @@ void netif_napi_add(struct net_device *d
#ifdef CONFIG_NETPOLL
napi->poll_owner = -1;
#endif
+ INIT_WORK(&napi->work, napi_workfn);
set_bit(NAPI_STATE_SCHED, &napi->state);
napi_hash_add(napi);
}
@@ -6276,6 +6366,7 @@ static void flush_gro_hash(struct napi_s
void netif_napi_del(struct napi_struct *napi)
{
might_sleep();
+ cancel_work_sync(&napi->work);
if (napi_hash_del(napi))
synchronize_net();
list_del_init(&napi->dev_list);
@@ -6288,50 +6379,18 @@ EXPORT_SYMBOL(netif_napi_del);
static int napi_poll(struct napi_struct *n, struct list_head *repoll)
{
+ bool do_repoll = false;
void *have;
- int work, weight;
+ int work;
list_del_init(&n->poll_list);
have = netpoll_poll_lock(n);
- weight = n->weight;
-
- /* This NAPI_STATE_SCHED test is for avoiding a race
- * with netpoll's poll_napi(). Only the entity which
- * obtains the lock and sees NAPI_STATE_SCHED set will
- * actually make the ->poll() call. Therefore we avoid
- * accidentally calling ->poll() when NAPI is not scheduled.
- */
- work = 0;
- if (test_bit(NAPI_STATE_SCHED, &n->state)) {
- work = n->poll(n, weight);
- trace_napi_poll(n, work, weight);
- }
-
- WARN_ON_ONCE(work > weight);
-
- if (likely(work < weight))
- goto out_unlock;
+ work = __napi_poll(n, &do_repoll);
- /* Drivers must not modify the NAPI state if they
- * consume the entire weight. In such cases this code
- * still "owns" the NAPI instance and therefore can
- * move the instance around on the list at-will.
- */
- if (unlikely(napi_disable_pending(n))) {
- napi_complete(n);
+ if (!do_repoll)
goto out_unlock;
- }
-
- if (n->gro_bitmask) {
- /* flush too old packets
- * If HZ < 1000, flush all packets.
- */
- napi_gro_flush(n, HZ >= 1000);
- }
-
- gro_normal_list(n);
/* Some drivers may have called napi_schedule
* prior to exhausting their budget.
@@ -10264,6 +10323,10 @@ static int __init net_dev_init(void)
sd->backlog.weight = weight_p;
}
+ napi_workq = alloc_workqueue("napi_workq", WQ_UNBOUND | WQ_HIGHPRI,
+ WQ_UNBOUND_MAX_ACTIVE | WQ_SYSFS);
+ BUG_ON(!napi_workq);
+
dev_boot_phase = 0;
/* The loopback device is special if any other network devices
--- a/net/core/net-sysfs.c
+++ b/net/core/net-sysfs.c
@@ -442,6 +442,52 @@ static ssize_t proto_down_store(struct d
}
NETDEVICE_SHOW_RW(proto_down, fmt_dec);
+static int change_napi_threaded(struct net_device *dev, unsigned long val)
+{
+ struct napi_struct *napi;
+
+ if (list_empty(&dev->napi_list))
+ return -EOPNOTSUPP;
+
+ list_for_each_entry(napi, &dev->napi_list, dev_list) {
+ if (val)
+ set_bit(NAPI_STATE_THREADED, &napi->state);
+ else
+ clear_bit(NAPI_STATE_THREADED, &napi->state);
+ }
+
+ return 0;
+}
+
+static ssize_t napi_threaded_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t len)
+{
+ return netdev_store(dev, attr, buf, len, change_napi_threaded);
+}
+
+static ssize_t napi_threaded_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct net_device *netdev = to_net_dev(dev);
+ struct napi_struct *napi;
+ bool enabled = false;
+
+ if (!rtnl_trylock())
+ return restart_syscall();
+
+ list_for_each_entry(napi, &netdev->napi_list, dev_list) {
+ if (test_bit(NAPI_STATE_THREADED, &napi->state))
+ enabled = true;
+ }
+
+ rtnl_unlock();
+
+ return sprintf(buf, fmt_dec, enabled);
+}
+static DEVICE_ATTR_RW(napi_threaded);
+
static ssize_t phys_port_id_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
@@ -532,6 +578,7 @@ static struct attribute *net_class_attrs
&dev_attr_flags.attr,
&dev_attr_tx_queue_len.attr,
&dev_attr_gro_flush_timeout.attr,
+ &dev_attr_napi_threaded.attr,
&dev_attr_phys_port_id.attr,
&dev_attr_phys_port_name.attr,
&dev_attr_phys_switch_id.attr,

View File

@ -1,7 +1,6 @@
// SPDX-License-Identifier: GPL-2.0-or-later OR MIT
#include "qcom-ipq8064-v2.0.dtsi"
#include <dt-bindings/input/input.h>
#include "qcom-ipq8064-eax500.dtsi"
/ {
model = "Linksys EA7500 V1 WiFi Router";
@ -20,10 +19,8 @@
};
chosen {
bootargs = "console=ttyMSM0,115200n8";
append-rootblock = "ubi.mtd="; /* append to bootargs adding the root deviceblock nbr from bootloader */
find-rootblock = "ubi.mtd="; /* look for root deviceblock nbr in this bootarg */
/* look for root deviceblock nbr in this bootarg */
find-rootblock = "ubi.mtd=";
};
keys {
@ -77,200 +74,14 @@
};
};
&usb3_0 {
status = "okay";
};
&partitions {
partition@5f80000 {
label = "sysdiag";
reg = <0x5f80000 0x100000>;
};
&usb3_1 {
status = "okay";
};
&pcie0 {
status = "okay";
force_gen1 = <1>;
};
&pcie1 {
status = "okay";
};
&pcie2 {
status = "okay";
};
&nand_controller {
status = "okay";
pinctrl-0 = <&nand_pins>;
pinctrl-names = "default";
nand@0 {
reg = <0>;
compatible = "qcom,nandcs";
nand-ecc-strength = <4>;
nand-bus-width = <8>;
nand-ecc-step-size = <512>;
partitions {
compatible = "fixed-partitions";
#address-cells = <1>;
#size-cells = <1>;
partition@0 {
label = "SBL1";
reg = <0x0000000 0x0040000>;
read-only;
};
partition@40000 {
label = "MIBIB";
reg = <0x0040000 0x0140000>;
read-only;
};
partition@180000 {
label = "SBL2";
reg = <0x0180000 0x0140000>;
read-only;
};
partition@2c0000 {
label = "SBL3";
reg = <0x02c0000 0x0280000>;
read-only;
};
partition@540000 {
label = "DDRCONFIG";
reg = <0x0540000 0x0120000>;
read-only;
};
partition@660000 {
label = "SSD";
reg = <0x0660000 0x0120000>;
read-only;
};
partition@780000 {
label = "TZ";
reg = <0x0780000 0x0280000>;
read-only;
};
partition@a00000 {
label = "RPM";
reg = <0x0a00000 0x0280000>;
read-only;
};
art: partition@c80000 {
label = "art";
reg = <0x0c80000 0x0140000>;
read-only;
};
partition@dc0000 {
label = "APPSBL";
reg = <0x0dc0000 0x0100000>;
read-only;
};
partition@ec0000 {
label = "u_env";
reg = <0x0ec0000 0x0040000>;
};
partition@f00000 {
label = "s_env";
reg = <0x0f00000 0x0040000>;
};
partition@f40000 {
label = "devinfo";
reg = <0x0f40000 0x0040000>;
};
partition@f80000 {
label = "kernel1";
reg = <0x0f80000 0x2800000>; /* 3 MB spill to rootfs*/
};
partition@1280000 {
label = "rootfs1";
reg = <0x1280000 0x2500000>;
};
partition@3780000 {
label = "kernel2";
reg = <0x3780000 0x2800000>;
};
partition@3a80000 {
label = "rootfs2";
reg = <0x3a80000 0x2500000>;
};
partition@5f80000 {
label = "sysdiag";
reg = <0x5f80000 0x100000>;
};
partition@6080000 {
label = "syscfg";
reg = <0x6080000 0x1f80000>;
};
};
partition@6080000 {
label = "syscfg";
reg = <0x6080000 0x1f80000>;
};
};
&mdio0 {
status = "okay";
pinctrl-0 = <&mdio0_pins>;
pinctrl-names = "default";
phy0: ethernet-phy@0 {
reg = <0>;
qca,ar8327-initvals = <
0x00004 0x7600000 /* PAD0_MODE */
0x00008 0x1000000 /* PAD5_MODE */
0x0000c 0x80 /* PAD6_MODE */
0x00010 0x2613a0 /* PWS_REG */
0x000e4 0x6a545 /* MAC_POWER_SEL */
0x000e0 0xc74164de /* SGMII_CTRL */
0x0007c 0x4e /* PORT0_STATUS */
0x00094 0x4e /* PORT6_STATUS */
>;
};
};
&gmac1 {
status = "okay";
phy-mode = "rgmii";
qcom,id = <1>;
pinctrl-0 = <&rgmii2_pins>;
pinctrl-names = "default";
fixed-link {
speed = <1000>;
full-duplex;
};
};
&gmac2 {
status = "okay";
phy-mode = "sgmii";
qcom,id = <2>;
fixed-link {
speed = <1000>;
full-duplex;
};
};
&adm_dma {
status = "okay";
};

View File

@ -1,6 +1,4 @@
#include "qcom-ipq8064-v2.0.dtsi"
#include <dt-bindings/input/input.h>
#include "qcom-ipq8064-eax500.dtsi"
/ {
model = "Linksys EA8500 WiFi Router";
@ -14,15 +12,10 @@
aliases {
mdio-gpio0 = &mdio0;
led-boot = &power;
led-failsafe = &power;
led-running = &power;
led-upgrade = &power;
};
chosen {
bootargs = "console=ttyMSM0,115200n8";
append-rootblock = "ubi.mtd="; /* append to bootargs adding the root deviceblock nbr from bootloader */
led-boot = &led_power;
led-failsafe = &led_power;
led-running = &led_power;
led-upgrade = &led_power;
};
keys {
@ -39,7 +32,7 @@
reset {
label = "reset";
gpios = <&qcom_pinmux 68 GPIO_ACTIVE_LOW>;
linux,code = <KEY_RESTART >;
linux,code = <KEY_RESTART>;
};
wps {
@ -59,7 +52,7 @@
gpios = <&qcom_pinmux 53 GPIO_ACTIVE_HIGH>;
};
power: power {
led_power: power {
label = "ea8500:white:power";
gpios = <&qcom_pinmux 6 GPIO_ACTIVE_LOW>;
default-state = "keep";
@ -100,204 +93,30 @@
status = "okay";
};
&usb3_0 {
status = "okay";
};
&usb3_1 {
status = "okay";
};
&pcie0 {
status = "okay";
force_gen1 = <1>;
};
&pcie1 {
status = "okay";
};
&pcie2 {
status = "okay";
};
&nand_controller {
status = "okay";
pinctrl-0 = <&nand_pins>;
pinctrl-names = "default";
nand@0 {
reg = <0>;
compatible = "qcom,nandcs";
nand-ecc-strength = <4>;
nand-bus-width = <8>;
nand-ecc-step-size = <512>;
partitions {
compatible = "fixed-partitions";
#address-cells = <1>;
#size-cells = <1>;
SBL1@0 {
label = "SBL1";
reg = <0x0000000 0x0040000>;
read-only;
};
MIBIB@40000 {
label = "MIBIB";
reg = <0x0040000 0x0140000>;
read-only;
};
SBL2@180000 {
label = "SBL2";
reg = <0x0180000 0x0140000>;
read-only;
};
SBL3@2c0000 {
label = "SBL3";
reg = <0x02c0000 0x0280000>;
read-only;
};
DDRCONFIG@540000 {
label = "DDRCONFIG";
reg = <0x0540000 0x0120000>;
read-only;
};
SSD@660000 {
label = "SSD";
reg = <0x0660000 0x0120000>;
read-only;
};
TZ@780000 {
label = "TZ";
reg = <0x0780000 0x0280000>;
read-only;
};
RPM@a00000 {
label = "RPM";
reg = <0x0a00000 0x0280000>;
read-only;
};
art: art@c80000 {
label = "art";
reg = <0x0c80000 0x0140000>;
read-only;
};
APPSBL@dc0000 {
label = "APPSBL";
reg = <0x0dc0000 0x0100000>;
read-only;
};
u_env@ec0000 {
label = "u_env";
reg = <0x0ec0000 0x0040000>;
};
s_env@f00000 {
label = "s_env";
reg = <0x0f00000 0x0040000>;
};
devinfo@f40000 {
label = "devinfo";
reg = <0x0f40000 0x0040000>;
};
linux@f80000 {
label = "kernel1";
reg = <0x0f80000 0x2800000>; /* 3 MB spill to rootfs*/
};
rootfs@1280000 {
label = "rootfs1";
reg = <0x1280000 0x2500000>;
};
linux2@3780000 {
label = "kernel2";
reg = <0x3780000 0x2800000>;
};
rootfs2@3a80000 {
label = "rootfs2";
reg = <0x3a80000 0x2500000>;
};
syscfg@5f80000 {
label = "syscfg";
reg = <0x5f80000 0x2080000>;
};
};
&partitions {
partition@5f80000 {
label = "syscfg";
reg = <0x5f80000 0x2080000>;
};
};
&mdio0 {
status = "okay";
pinctrl-0 = <&mdio0_pins>;
pinctrl-names = "default";
phy0: ethernet-phy@0 {
reg = <0>;
qca,ar8327-initvals = <
0x00004 0x7600000 /* PAD0_MODE */
0x00008 0x1000000 /* PAD5_MODE */
0x0000c 0x80 /* PAD6_MODE */
0x00010 0x2613a0 /* PWS_REG */
0x000e4 0x6a545 /* MAC_POWER_SEL */
0x000e0 0xc74164de /* SGMII_CTRL */
0x0007c 0x4e /* PORT0_STATUS */
0x00094 0x4e /* PORT6_STATUS */
>;
};
phy4: ethernet-phy@4 {
reg = <4>;
};
};
&gmac1 {
status = "okay";
phy-mode = "rgmii";
qcom,id = <1>;
qcom,phy_mdio_addr = <4>;
qcom,poll_required = <1>;
qcom,rgmii_delay = <0>;
qcom,emulation = <0>;
pinctrl-0 = <&rgmii2_pins>;
pinctrl-names = "default";
fixed-link {
speed = <1000>;
full-duplex;
};
};
/* LAN */
&gmac2 {
status = "okay";
phy-mode = "sgmii";
qcom,id = <2>;
qcom,phy_mdio_addr = <0>; /* none */
qcom,poll_required = <0>; /* no polling */
qcom,rgmii_delay = <0>;
qcom,emulation = <0>;
fixed-link {
speed = <1000>;
full-duplex;
};
};
&adm_dma {
status = "okay";
};

View File

@ -0,0 +1,204 @@
// SPDX-License-Identifier: GPL-2.0-or-later OR MIT
#include "qcom-ipq8064-v2.0.dtsi"
#include <dt-bindings/input/input.h>
/ {
chosen {
bootargs = "console=ttyMSM0,115200n8";
/* append to bootargs adding the root deviceblock nbr from bootloader */
append-rootblock = "ubi.mtd=";
};
};
&usb3_0 {
status = "okay";
};
&usb3_1 {
status = "okay";
};
&pcie0 {
status = "okay";
force_gen1 = <1>;
};
&pcie1 {
status = "okay";
};
&pcie2 {
status = "okay";
};
&nand_controller {
status = "okay";
pinctrl-0 = <&nand_pins>;
pinctrl-names = "default";
nand@0 {
reg = <0>;
compatible = "qcom,nandcs";
nand-ecc-strength = <4>;
nand-bus-width = <8>;
nand-ecc-step-size = <512>;
partitions: partitions {
compatible = "fixed-partitions";
#address-cells = <1>;
#size-cells = <1>;
partition@0 {
label = "SBL1";
reg = <0x0000000 0x0040000>;
read-only;
};
partition@40000 {
label = "MIBIB";
reg = <0x0040000 0x0140000>;
read-only;
};
partition@180000 {
label = "SBL2";
reg = <0x0180000 0x0140000>;
read-only;
};
partition@2c0000 {
label = "SBL3";
reg = <0x02c0000 0x0280000>;
read-only;
};
partition@540000 {
label = "DDRCONFIG";
reg = <0x0540000 0x0120000>;
read-only;
};
partition@660000 {
label = "SSD";
reg = <0x0660000 0x0120000>;
read-only;
};
partition@780000 {
label = "TZ";
reg = <0x0780000 0x0280000>;
read-only;
};
partition@a00000 {
label = "RPM";
reg = <0x0a00000 0x0280000>;
read-only;
};
art: partition@c80000 {
label = "art";
reg = <0x0c80000 0x0140000>;
read-only;
};
partition@dc0000 {
label = "APPSBL";
reg = <0x0dc0000 0x0100000>;
read-only;
};
partition@ec0000 {
label = "u_env";
reg = <0x0ec0000 0x0040000>;
};
partition@f00000 {
label = "s_env";
reg = <0x0f00000 0x0040000>;
};
partition@f40000 {
label = "devinfo";
reg = <0x0f40000 0x0040000>;
};
partition@f80000 {
label = "kernel1";
reg = <0x0f80000 0x2800000>; /* 3 MB spill to rootfs */
};
partition@1280000 {
label = "rootfs1";
reg = <0x1280000 0x2500000>;
};
partition@3780000 {
label = "kernel2";
reg = <0x3780000 0x2800000>;
};
partition@3a80000 {
label = "rootfs2";
reg = <0x3a80000 0x2500000>;
};
};
};
};
&mdio0 {
status = "okay";
pinctrl-0 = <&mdio0_pins>;
pinctrl-names = "default";
phy0: ethernet-phy@0 {
reg = <0>;
qca,ar8327-initvals = <
0x00004 0x7600000 /* PAD0_MODE */
0x00008 0x1000000 /* PAD5_MODE */
0x0000c 0x80 /* PAD6_MODE */
0x00010 0x2613a0 /* PWS_REG */
0x000e4 0x6a545 /* MAC_POWER_SEL */
0x000e0 0xc74164de /* SGMII_CTRL */
0x0007c 0x4e /* PORT0_STATUS */
0x00094 0x4e /* PORT6_STATUS */
>;
};
};
&gmac1 {
status = "okay";
phy-mode = "rgmii";
qcom,id = <1>;
pinctrl-0 = <&rgmii2_pins>;
pinctrl-names = "default";
fixed-link {
speed = <1000>;
full-duplex;
};
};
&gmac2 {
status = "okay";
phy-mode = "sgmii";
qcom,id = <2>;
fixed-link {
speed = <1000>;
full-duplex;
};
};
&adm_dma {
status = "okay";
};

View File

@ -21,16 +21,10 @@ BOARD:=uml
BOARDNAME:=User Mode Linux
FEATURES:=squashfs ext4 audio source-only
KERNEL_PATCHVER:=4.14
KERNEL_PATCHVER:=5.4
include $(INCLUDE_DIR)/target.mk
define Kernel/Patch
mkdir -p $(LINUX_DIR)/arch/um/include/uapi
mv $(LINUX_DIR)/arch/um/include/asm $(LINUX_DIR)/arch/um/include/uapi/
$(Kernel/Patch/Default)
endef
LINUX_TARGET_CONFIG:=$(CURDIR)/config/$(ARCH)
DEFAULT_PACKAGES += wpad-basic-wolfssl kmod-mac80211-hwsim mkf2fs e2fsprogs

View File

@ -1,76 +1,62 @@
# CONFIG_3_LEVEL_PGTABLES is not set
# CONFIG_64BIT is not set
CONFIG_ARCH_DEFCONFIG="arch/um/configs/i386_defconfig"
# CONFIG_ARCH_HAS_GCOV_PROFILE_ALL is not set
CONFIG_ARCH_HAS_KCOV=y
CONFIG_ARCH_HAS_SC_SIGNALS=y
# CONFIG_ARCH_HAS_SG_CHAIN is not set
# CONFIG_ARCH_HAS_STRICT_KERNEL_RWX is not set
# CONFIG_ARCH_HAS_STRICT_MODULE_RWX is not set
# CONFIG_ARCH_OPTIONAL_KERNEL_RWX is not set
# CONFIG_ARCH_OPTIONAL_KERNEL_RWX_DEFAULT is not set
CONFIG_ARCH_REUSE_HOST_VSYSCALL_AREA=y
CONFIG_ARCH_WANT_IPC_PARSE_VERSION=y
CONFIG_ARCH_NO_PREEMPT=y
CONFIG_BLK_DEV_COW_COMMON=y
CONFIG_BLK_DEV_LOOP=y
CONFIG_BLK_DEV_UBD=y
CONFIG_BLK_DEV_UBD_SYNC=y
CONFIG_CLONE_BACKWARDS=y
CONFIG_BLK_MQ_VIRTIO=y
CONFIG_CC_HAS_KASAN_GENERIC=y
CONFIG_CON_CHAN="xterm"
CONFIG_CON_ZERO_CHAN="fd:0,fd:1"
CONFIG_CPU_SUP_AMD=y
CONFIG_CPU_SUP_CENTAUR=y
CONFIG_CPU_SUP_CYRIX_32=y
CONFIG_CPU_SUP_HYGON=y
CONFIG_CPU_SUP_INTEL=y
CONFIG_CPU_SUP_TRANSMETA_32=y
CONFIG_CPU_SUP_UMC_32=y
# CONFIG_CRASHLOG is not set
CONFIG_CPU_SUP_ZHAOXIN=y
CONFIG_CRC16=y
CONFIG_CRYPTO_CRC32=y
CONFIG_CRYPTO_CRC32C=y
CONFIG_CRYPTO_HASH=y
CONFIG_CRYPTO_HASH2=y
CONFIG_CRYPTO_RNG2=y
CONFIG_CRYPTO_WORKQUEUE=y
CONFIG_CRYPTO_SHA1=y
CONFIG_DEBUG_MEMORY_INIT=y
CONFIG_DECOMPRESS_BZIP2=y
CONFIG_DECOMPRESS_GZIP=y
CONFIG_DEFAULT_CFQ=y
# CONFIG_DEFAULT_DEADLINE is not set
CONFIG_DEFAULT_IOSCHED="cfq"
CONFIG_DNOTIFY=y
# CONFIG_EARLY_PRINTK is not set
# CONFIG_EMBEDDED is not set
CONFIG_EXT4_FS=y
# CONFIG_F2FS_CHECK_FS is not set
CONFIG_F2FS_FS=y
# CONFIG_F2FS_FS_SECURITY is not set
CONFIG_F2FS_FS_XATTR=y
CONFIG_F2FS_STAT_FS=y
CONFIG_FAILOVER=y
CONFIG_FS_IOMAP=y
CONFIG_FS_MBCACHE=y
CONFIG_FW_LOADER_PAGED_BUF=y
CONFIG_GENERIC_CLOCKEVENTS=y
# CONFIG_GENERIC_CPU is not set
CONFIG_GENERIC_CPU_DEVICES=y
CONFIG_GENERIC_FIND_FIRST_BIT=y
CONFIG_GENERIC_IO=y
CONFIG_GENERIC_IRQ_SHOW=y
# CONFIG_GRO_CELLS is not set
# CONFIG_HAVE_64BIT_ALIGNED_ACCESS is not set
CONFIG_HAVE_AOUT=y
CONFIG_HAVE_ARCH_AUDITSYSCALL=y
# CONFIG_HAVE_ARCH_BITREVERSE is not set
CONFIG_HAVE_ARCH_SECCOMP_FILTER=y
# CONFIG_HAVE_BOOTMEM_INFO_NODE is not set
CONFIG_HAVE_ASM_MODVERSIONS=y
CONFIG_HAVE_COPY_THREAD_TLS=y
CONFIG_HAVE_DEBUG_BUGVERBOSE=y
CONFIG_HAVE_DEBUG_KMEMLEAK=y
CONFIG_HAVE_FUTEX_CMPXCHG=y
# CONFIG_HAVE_GENERIC_DMA_COHERENT is not set
CONFIG_HAVE_NET_DSA=y
CONFIG_HAVE_UID16=y
CONFIG_HOSTAUDIO=m
CONFIG_HAVE_VIRT_CPU_ACCOUNTING_GEN=y
CONFIG_HOSTFS=y
CONFIG_HVC_DRIVER=y
CONFIG_HZ=100
CONFIG_HZ_PERIODIC=y
CONFIG_INITRAMFS_SOURCE=""
CONFIG_INIT_ENV_ARG_LIMIT=128
CONFIG_IOSCHED_CFQ=y
CONFIG_IRQ_WORK=y
CONFIG_ISO9660_FS=y
CONFIG_JBD2=y
@ -78,68 +64,38 @@ CONFIG_JBD2=y
CONFIG_KALLSYMS=y
CONFIG_KERNEL_STACK_ORDER=2
CONFIG_LD_SCRIPT_STATIC=y
# CONFIG_M486 is not set
# CONFIG_M586 is not set
# CONFIG_M586MMX is not set
# CONFIG_M586TSC is not set
# CONFIG_M686 is not set
CONFIG_MAGIC_SYSRQ=y
CONFIG_LOCK_DEBUGGING_SUPPORT=y
# CONFIG_MATOM is not set
CONFIG_MCONSOLE=y
# CONFIG_MCORE2 is not set
# CONFIG_MCRUSOE is not set
# CONFIG_MCYRIXIII is not set
# CONFIG_MDIO_BUS is not set
# CONFIG_MEFFICEON is not set
# CONFIG_MELAN is not set
# CONFIG_MGEODEGX1 is not set
# CONFIG_MGEODE_LX is not set
# CONFIG_MK6 is not set
# CONFIG_MK7 is not set
# CONFIG_MK8 is not set
CONFIG_MEMFD_CREATE=y
CONFIG_MIGRATION=y
CONFIG_MK8=y
# CONFIG_MMAPPER is not set
CONFIG_MODULES_USE_ELF_REL=y
# CONFIG_MPENTIUM4 is not set
CONFIG_MPENTIUMII=y
# CONFIG_MPENTIUMIII is not set
# CONFIG_MPENTIUMM is not set
# CONFIG_MVIAC3_2 is not set
# CONFIG_MVIAC7 is not set
# CONFIG_MWINCHIP3D is not set
# CONFIG_MWINCHIPC6 is not set
CONFIG_MODULES_USE_ELF_RELA=y
# CONFIG_MPSC is not set
CONFIG_NAMESPACES=y
CONFIG_NEED_PER_CPU_KM=y
CONFIG_NET_FAILOVER=y
# CONFIG_NET_NS is not set
CONFIG_NLS=y
# CONFIG_NOCONFIG_CHAN is not set
CONFIG_NO_DMA=y
CONFIG_NO_IOMEM=y
CONFIG_NR_CPUS=1
# CONFIG_NSC_GPIO is not set
CONFIG_NULL_CHAN=y
# CONFIG_OF is not set
CONFIG_OLD_SIGACTION=y
CONFIG_OLD_SIGSUSPEND3=y
CONFIG_PGTABLE_LEVELS=2
CONFIG_PGTABLE_LEVELS=3
CONFIG_PHYS_ADDR_T_64BIT=y
CONFIG_PORT_CHAN=y
CONFIG_POSIX_MQUEUE=y
CONFIG_POSIX_MQUEUE_SYSCTL=y
# CONFIG_PROCESSOR_SELECT is not set
CONFIG_PROC_PAGE_MONITOR=y
CONFIG_PTY_CHAN=y
# CONFIG_RCU_NEED_SEGCBLIST is not set
# CONFIG_RCU_STALL_COMMON is not set
CONFIG_RD_BZIP2=y
CONFIG_RD_GZIP=y
CONFIG_RELAY=y
# CONFIG_RWSEM_XCHGADD_ALGORITHM is not set
# CONFIG_SBC8360_WDT is not set
# CONFIG_SCHED_INFO is not set
# CONFIG_SCSI_DMA is not set
CONFIG_SOFT_WATCHDOG=m
CONFIG_SOUND=m
CONFIG_SOUND_OSS_CORE=y
CONFIG_SOUND_OSS_CORE_PRECLAIM=y
CONFIG_SRCU=y
CONFIG_SSL=y
CONFIG_SSL_CHAN="pty"
@ -152,19 +108,26 @@ CONFIG_TTY_CHAN=y
CONFIG_UML=y
CONFIG_UML_NET=y
CONFIG_UML_NET_DAEMON=y
CONFIG_UML_NET_DETERMINISTIC_MAC=y
CONFIG_UML_NET_ETHERTAP=y
CONFIG_UML_NET_MCAST=y
# CONFIG_UML_NET_PCAP is not set
# CONFIG_UML_NET_RANDOM_MAC is not set
CONFIG_UML_NET_SLIP=y
CONFIG_UML_NET_SLIRP=y
CONFIG_UML_NET_TUNTAP=y
# CONFIG_UML_NET_VDE is not set
CONFIG_UML_NET_VECTOR=y
CONFIG_UML_RANDOM=y
CONFIG_UML_SOUND=m
CONFIG_UML_WATCHDOG=m
# CONFIG_UML_SOUND is not set
CONFIG_UML_TIME_TRAVEL_SUPPORT=y
CONFIG_UML_WATCHDOG=y
CONFIG_UML_X86=y
# CONFIG_USER_NS is not set
CONFIG_VIRTIO=y
CONFIG_VIRTIO_BLK=y
CONFIG_VIRTIO_CONSOLE=y
CONFIG_VIRTIO_NET=y
CONFIG_VIRTIO_UML=y
CONFIG_VM_EVENT_COUNTERS=y
CONFIG_WATCHDOG_CORE=y
CONFIG_X86_32=y

View File

@ -1,75 +1,64 @@
CONFIG_3_LEVEL_PGTABLES=y
CONFIG_64BIT=y
CONFIG_ARCH_DEFCONFIG="arch/um/configs/x86_64_defconfig"
# CONFIG_ARCH_HAS_GCOV_PROFILE_ALL is not set
CONFIG_ARCH_DMA_ADDR_T_64BIT=y
CONFIG_ARCH_HAS_KCOV=y
# CONFIG_ARCH_HAS_SC_SIGNALS is not set
# CONFIG_ARCH_HAS_SG_CHAIN is not set
# CONFIG_ARCH_HAS_STRICT_KERNEL_RWX is not set
# CONFIG_ARCH_HAS_STRICT_MODULE_RWX is not set
# CONFIG_ARCH_OPTIONAL_KERNEL_RWX is not set
# CONFIG_ARCH_OPTIONAL_KERNEL_RWX_DEFAULT is not set
# CONFIG_ARCH_REUSE_HOST_VSYSCALL_AREA is not set
CONFIG_ARCH_NO_PREEMPT=y
CONFIG_BLK_DEV_COW_COMMON=y
CONFIG_BLK_DEV_LOOP=y
CONFIG_BLK_DEV_UBD=y
CONFIG_BLK_DEV_UBD_SYNC=y
CONFIG_BLK_MQ_VIRTIO=y
CONFIG_CC_HAS_KASAN_GENERIC=y
CONFIG_CON_CHAN="xterm"
CONFIG_CON_ZERO_CHAN="fd:0,fd:1"
CONFIG_CPU_SUP_AMD=y
CONFIG_CPU_SUP_CENTAUR=y
CONFIG_CPU_SUP_HYGON=y
CONFIG_CPU_SUP_INTEL=y
# CONFIG_CRASHLOG is not set
CONFIG_CPU_SUP_ZHAOXIN=y
CONFIG_CRC16=y
# CONFIG_CRYPTO_AES_X86_64 is not set
CONFIG_CRYPTO_CRC32=y
CONFIG_CRYPTO_CRC32C=y
CONFIG_CRYPTO_HASH=y
CONFIG_CRYPTO_HASH2=y
CONFIG_CRYPTO_RNG2=y
CONFIG_CRYPTO_SHA1=y
# CONFIG_CRYPTO_SKEIN is not set
# CONFIG_CRYPTO_TWOFISH_X86_64 is not set
CONFIG_CRYPTO_WORKQUEUE=y
CONFIG_DEBUG_MEMORY_INIT=y
CONFIG_DECOMPRESS_BZIP2=y
CONFIG_DECOMPRESS_GZIP=y
CONFIG_DEFAULT_CFQ=y
# CONFIG_DEFAULT_DEADLINE is not set
CONFIG_DEFAULT_IOSCHED="cfq"
CONFIG_DNOTIFY=y
# CONFIG_EARLY_PRINTK is not set
CONFIG_EXT4_FS=y
# CONFIG_F2FS_CHECK_FS is not set
CONFIG_F2FS_FS=y
# CONFIG_F2FS_FS_SECURITY is not set
CONFIG_F2FS_FS_XATTR=y
CONFIG_F2FS_STAT_FS=y
CONFIG_FAILOVER=y
CONFIG_FS_IOMAP=y
CONFIG_FS_MBCACHE=y
CONFIG_FW_LOADER_PAGED_BUF=y
CONFIG_GENERIC_CLOCKEVENTS=y
# CONFIG_GENERIC_CPU is not set
CONFIG_GENERIC_CPU_DEVICES=y
CONFIG_GENERIC_FIND_FIRST_BIT=y
CONFIG_GENERIC_IO=y
CONFIG_GENERIC_IRQ_SHOW=y
# CONFIG_GRO_CELLS is not set
CONFIG_HAVE_64BIT_ALIGNED_ACCESS=y
CONFIG_HAVE_ARCH_AUDITSYSCALL=y
# CONFIG_HAVE_ARCH_BITREVERSE is not set
CONFIG_HAVE_ARCH_SECCOMP_FILTER=y
# CONFIG_HAVE_BOOTMEM_INFO_NODE is not set
CONFIG_HAVE_ASM_MODVERSIONS=y
CONFIG_HAVE_COPY_THREAD_TLS=y
CONFIG_HAVE_DEBUG_BUGVERBOSE=y
CONFIG_HAVE_DEBUG_KMEMLEAK=y
CONFIG_HAVE_FUTEX_CMPXCHG=y
# CONFIG_HAVE_GENERIC_DMA_COHERENT is not set
CONFIG_HAVE_NET_DSA=y
CONFIG_HAVE_UID16=y
CONFIG_HAVE_VIRT_CPU_ACCOUNTING_GEN=y
CONFIG_HOSTAUDIO=m
CONFIG_HOSTFS=y
CONFIG_HVC_DRIVER=y
CONFIG_HZ=100
CONFIG_HZ_PERIODIC=y
CONFIG_INITRAMFS_SOURCE=""
CONFIG_INIT_ENV_ARG_LIMIT=128
CONFIG_IOSCHED_CFQ=y
CONFIG_IRQ_WORK=y
CONFIG_ISO9660_FS=y
CONFIG_JBD2=y
@ -77,19 +66,21 @@ CONFIG_JBD2=y
CONFIG_KALLSYMS=y
CONFIG_KERNEL_STACK_ORDER=2
CONFIG_LD_SCRIPT_STATIC=y
CONFIG_LOCK_DEBUGGING_SUPPORT=y
# CONFIG_MATOM is not set
CONFIG_MCONSOLE=y
# CONFIG_MCORE2 is not set
# CONFIG_MDIO_BUS is not set
CONFIG_MEMFD_CREATE=y
CONFIG_MIGRATION=y
CONFIG_MK8=y
# CONFIG_MMAPPER is not set
CONFIG_MODULES_USE_ELF_RELA=y
# CONFIG_MPSC is not set
CONFIG_NAMESPACES=y
CONFIG_NEED_PER_CPU_KM=y
CONFIG_NET_FAILOVER=y
# CONFIG_NET_NS is not set
CONFIG_NLS=y
# CONFIG_NOCONFIG_CHAN is not set
CONFIG_NO_DMA=y
CONFIG_NO_IOMEM=y
CONFIG_NR_CPUS=1
@ -103,19 +94,10 @@ CONFIG_POSIX_MQUEUE_SYSCTL=y
# CONFIG_PROCESSOR_SELECT is not set
CONFIG_PROC_PAGE_MONITOR=y
CONFIG_PTY_CHAN=y
# CONFIG_RCU_NEED_SEGCBLIST is not set
# CONFIG_RCU_STALL_COMMON is not set
CONFIG_RD_BZIP2=y
CONFIG_RD_GZIP=y
CONFIG_RELAY=y
# CONFIG_RWSEM_GENERIC_SPINLOCK is not set
CONFIG_RWSEM_XCHGADD_ALGORITHM=y
# CONFIG_SCHED_INFO is not set
# CONFIG_SCSI_DMA is not set
CONFIG_SOFT_WATCHDOG=m
CONFIG_SOUND=m
CONFIG_SOUND_OSS_CORE=y
CONFIG_SOUND_OSS_CORE_PRECLAIM=y
CONFIG_SRCU=y
CONFIG_SSL=y
CONFIG_SSL_CHAN="pty"
@ -128,22 +110,28 @@ CONFIG_TTY_CHAN=y
CONFIG_UML=y
CONFIG_UML_NET=y
CONFIG_UML_NET_DAEMON=y
CONFIG_UML_NET_DETERMINISTIC_MAC=y
CONFIG_UML_NET_ETHERTAP=y
CONFIG_UML_NET_MCAST=y
# CONFIG_UML_NET_PCAP is not set
# CONFIG_UML_NET_RANDOM_MAC is not set
CONFIG_UML_NET_SLIP=y
CONFIG_UML_NET_SLIRP=y
CONFIG_UML_NET_TUNTAP=y
# CONFIG_UML_NET_VDE is not set
CONFIG_UML_NET_VECTOR=y
CONFIG_UML_RANDOM=y
CONFIG_UML_SOUND=m
CONFIG_UML_WATCHDOG=m
# CONFIG_UML_SOUND is not set
CONFIG_UML_TIME_TRAVEL_SUPPORT=y
CONFIG_UML_WATCHDOG=y
CONFIG_UML_X86=y
# CONFIG_USER_NS is not set
CONFIG_VIRTIO=y
CONFIG_VIRTIO_BLK=y
CONFIG_VIRTIO_CONSOLE=y
CONFIG_VIRTIO_NET=y
CONFIG_VIRTIO_UML=y
CONFIG_VM_EVENT_COUNTERS=y
CONFIG_WATCHDOG_CORE=y
# CONFIG_X86_32 is not set
CONFIG_X86_64=y
CONFIG_X86_CMOV=y
CONFIG_X86_CMPXCHG64=y

View File

@ -28,7 +28,7 @@
--- a/arch/um/drivers/mconsole_kern.c
+++ b/arch/um/drivers/mconsole_kern.c
@@ -4,6 +4,7 @@
* Licensed under the GPL
* Copyright (C) 2001 - 2008 Jeff Dike (jdike@{addtoit,linux.intel}.com)
*/
+#include <linux/kmod.h>
@ -43,7 +43,7 @@
#include <asm/switch_to.h>
#include <init.h>
@@ -122,6 +124,59 @@ void mconsole_log(struct mc_request *req
@@ -121,6 +123,59 @@ void mconsole_log(struct mc_request *req
mconsole_reply(req, "", 0, 0);
}
@ -123,7 +123,7 @@
};
--- a/arch/um/os-Linux/file.c
+++ b/arch/um/os-Linux/file.c
@@ -555,6 +555,8 @@ int os_create_unix_socket(const char *fi
@@ -557,6 +557,8 @@ int os_create_unix_socket(const char *fi
addr.sun_family = AF_UNIX;
@ -134,7 +134,7 @@
err = bind(sock, (struct sockaddr *) &addr, sizeof(addr));
--- a/include/linux/kmod.h
+++ b/include/linux/kmod.h
@@ -45,4 +45,6 @@ static inline int request_module_nowait(
@@ -32,4 +32,6 @@ static inline int request_module_nowait(
#define try_then_request_module(x, mod...) (x)
#endif
@ -143,25 +143,17 @@
#endif /* __LINUX_KMOD_H__ */
--- a/include/linux/umh.h
+++ b/include/linux/umh.h
@@ -22,6 +22,7 @@ struct subprocess_info {
const char *path;
@@ -23,6 +23,7 @@ struct subprocess_info {
char **argv;
char **envp;
struct file *file;
+ struct file *stdout;
int wait;
int retval;
int (*init)(struct subprocess_info *info, struct cred *new);
pid_t pid;
--- a/kernel/umh.c
+++ b/kernel/umh.c
@@ -25,6 +25,7 @@
#include <linux/ptrace.h>
#include <linux/async.h>
#include <linux/uaccess.h>
+#include <linux/pipe_fs_i.h>
#include <trace/events/module.h>
@@ -70,6 +71,28 @@ static int call_usermodehelper_exec_asyn
@@ -75,6 +75,28 @@ static int call_usermodehelper_exec_asyn
flush_signal_handlers(current, 1);
spin_unlock_irq(&current->sighand->siglock);
@ -190,9 +182,9 @@
/*
* Our parent (unbound workqueue) runs with elevated scheduling
* priority. Avoid propagating that into the userspace child.
@@ -393,6 +416,20 @@ struct subprocess_info *call_usermodehel
@@ -353,6 +375,20 @@ static void helper_unlock(void)
wake_up(&running_helpers_waitq);
}
EXPORT_SYMBOL(call_usermodehelper_setup);
+int call_usermodehelper_stdoutpipe(struct subprocess_info *sub_info,
+ struct file **filp)
@ -209,5 +201,5 @@
+EXPORT_SYMBOL(call_usermodehelper_stdoutpipe);
+
/**
* call_usermodehelper_exec - start a usermode application
* @sub_info: information about the subprocessa
* call_usermodehelper_setup - prepare to call a usermode helper
* @path: path to usermode executable

View File

@ -9,16 +9,17 @@ TECHNICAL INFORMATION:
Applies to vanilla kernel 3.9.4.
===============================================================================
--- a/arch/um/Kconfig.net
+++ b/arch/um/Kconfig.net
@@ -22,6 +22,19 @@ config UML_NET
enable at least one of the following transport options to actually
make use of UML networking.
--- a/arch/um/drivers/Kconfig
+++ b/arch/um/drivers/Kconfig
@@ -146,6 +146,20 @@ config UML_NET
enable at least one of the following transport options to actually
make use of UML networking.
+config UML_NET_RANDOM_MAC
+ bool "Use random MAC addresses for network interfaces"
+ default n
+config UML_NET_DETERMINISTIC_MAC
+ bool "Use deterministic MAC addresses for network interfaces"
+ default y
+ depends on UML_NET
+ select CRYPTO_SHA1
+ help
+ Virtual network devices inside a User-Mode Linux instance must be
+ assigned a MAC (Ethernet) address. If none is specified on the UML
@ -48,11 +49,11 @@ Applies to vanilla kernel 3.9.4.
#define DRIVER_NAME "uml-netdev"
static DEFINE_SPINLOCK(opened_lock);
@@ -288,11 +296,53 @@ static void uml_net_user_timer_expire(un
@@ -286,9 +294,51 @@ static void uml_net_user_timer_expire(st
#endif
}
+#ifndef CONFIG_UML_NET_RANDOM_MAC
+#ifdef CONFIG_UML_NET_DETERMINISTIC_MAC
+
+/* Compute a SHA1 hash of the UML instance's id and
+ * * an interface name. */
@ -93,20 +94,18 @@ Applies to vanilla kernel 3.9.4.
+
+#endif
+
static void setup_etheraddr(struct net_device *dev, char *str)
void uml_net_setup_etheraddr(struct net_device *dev, char *str)
{
unsigned char *addr = dev->dev_addr;
+ u8 hash[SHA1_DIGEST_SIZE];
char *end;
int i;
+ u8 hash[SHA1_DIGEST_SIZE];
if (str == NULL)
goto random;
@@ -333,9 +383,26 @@ static void setup_etheraddr(struct net_d
@@ -331,9 +381,26 @@ void uml_net_setup_etheraddr(struct net_
return;
random:
+#ifdef CONFIG_UML_NET_RANDOM_MAC
+#ifndef CONFIG_UML_NET_DETERMINISTIC_MAC
printk(KERN_INFO
"Choosing a random ethernet address for device %s\n", dev->name);
eth_hw_addr_random(dev);