Merge Official Source
This commit is contained in:
commit
008fd8bf4f
@ -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;
|
||||
@ -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)
|
||||
@ -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().
|
||||
@ -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)
|
||||
@ -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;
|
||||
@ -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);
|
||||
|
||||
@ -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)
|
||||
@ -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,
|
||||
@ -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;
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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
|
||||
@ -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);
|
||||
|
||||
@ -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;
|
||||
@ -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 */
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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 {
|
||||
|
||||
@ -6,15 +6,6 @@
|
||||
aliases {
|
||||
label-mac-device = ð0;
|
||||
};
|
||||
|
||||
gpio-export {
|
||||
compatible = "gpio-export";
|
||||
|
||||
led_control {
|
||||
gpio-export,name = "tp-link:led:control";
|
||||
gpios = <&gpio 14 GPIO_ACTIVE_HIGH>;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
&partitions {
|
||||
|
||||
@ -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);
|
||||
@ -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);
|
||||
|
||||
|
||||
@ -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);
|
||||
|
||||
|
||||
@ -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);
|
||||
|
||||
|
||||
@ -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,
|
||||
@ -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,
|
||||
@ -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,
|
||||
@ -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";
|
||||
};
|
||||
|
||||
@ -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";
|
||||
};
|
||||
|
||||
@ -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";
|
||||
};
|
||||
@ -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
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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(¤t->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
|
||||
@ -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);
|
||||
Loading…
Reference in New Issue
Block a user