Commit 6aea26ce authored by Felix Fietkau's avatar Felix Fietkau Committed by Johannes Berg
Browse files

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: default avatarFelix Fietkau <nbd@nbd.name>
Link: https://lore.kernel.org/r/20200908123702.88454-6-nbd@nbd.name


[resolved conflict with commit aa2092a9 ("ath11k: add raw mode and
software crypto support")]
Signed-off-by: default avatarJohannes Berg <johannes.berg@intel.com>
parent ae045152
Loading
Loading
Loading
Loading
+34 −27
Original line number Diff line number Diff line
@@ -4349,6 +4349,37 @@ static int ath11k_set_he_mu_sounding_mode(struct ath11k *ar,
	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 if (test_bit(ATH11K_FLAG_RAW_MODE, &ab->dev_flags))
		param_value = ATH11K_HW_TXRX_RAW;
	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)
{
@@ -4358,7 +4389,6 @@ static int ath11k_mac_op_add_interface(struct ieee80211_hw *hw,
	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;
@@ -4452,32 +4482,7 @@ static int ath11k_mac_op_add_interface(struct ieee80211_hw *hw,
	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 if (test_bit(ATH11K_FLAG_RAW_MODE, &ab->dev_flags))
		param_value = ATH11K_HW_TXRX_RAW;
	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,
@@ -5840,6 +5845,7 @@ static const struct ieee80211_ops ath11k_ops = {
	.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,
@@ -6148,6 +6154,7 @@ static int __ath11k_mac_register(struct ath11k *ar)
	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);
+29 −0
Original line number Diff line number Diff line
@@ -1606,6 +1606,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
 *
@@ -1626,6 +1641,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
@@ -1662,6 +1682,7 @@ struct ieee80211_vif {
	struct ieee80211_chanctx_conf __rcu *chanctx_conf;

	u32 driver_flags;
	u32 offload_flags;

#ifdef CONFIG_MAC80211_DEBUGFS
	struct dentry *debugfs_dir;
@@ -2328,6 +2349,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 {
@@ -2380,6 +2404,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
@@ -3814,6 +3839,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,
@@ -4125,6 +4152,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);
};

/**
+1 −0
Original line number Diff line number Diff line
@@ -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
};

+15 −0
Original line number Diff line number Diff line
@@ -1384,4 +1384,19 @@ static inline int drv_reset_tid_config(struct ieee80211_local *local,

	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 */
+1 −2
Original line number Diff line number Diff line
@@ -989,8 +989,6 @@ struct ieee80211_sub_if_data {
	} debugfs;
#endif

	bool hw_80211_encap;

	/* must be last, dynamically sized area in this! */
	struct ieee80211_vif vif;
};
@@ -1767,6 +1765,7 @@ void ieee80211_del_virtual_monitor(struct ieee80211_local *local);
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)
{
Loading