ath11k: add tx hw 802.11 encapsulation offloading support
authorJohn Crispin <john@phrozen.org>
Tue, 5 May 2020 07:42:03 +0000 (10:42 +0300)
committerKalle Valo <kvalo@codeaurora.org>
Wed, 6 May 2020 06:13:38 +0000 (09:13 +0300)
This patch adds support for ethernet rxtx mode to the driver. The feature
is enabled via a new module parameter. If enabled to driver will enable
the feature on a per vif basis if all other requirements were met.

Signed-off-by: Shashidhar Lakkavalli <slakkavalli@datto.com>
Signed-off-by: John Crispin <john@phrozen.org>
Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
Link: https://lore.kernel.org/r/20200430152814.18481-1-john@phrozen.org
drivers/net/wireless/ath/ath11k/core.h
drivers/net/wireless/ath/ath11k/dp_tx.c
drivers/net/wireless/ath/ath11k/mac.c
drivers/net/wireless/ath/ath11k/wmi.h

index 33237ea..70ec544 100644 (file)
@@ -60,9 +60,14 @@ static inline enum wme_ac ath11k_tid_to_ac(u32 tid)
                WME_AC_VO);
 }
 
+enum ath11k_skb_flags {
+       ATH11K_SKB_HW_80211_ENCAP = BIT(0),
+};
+
 struct ath11k_skb_cb {
        dma_addr_t paddr;
        u8 eid;
+       u8 flags;
        struct ath11k *ar;
        struct ieee80211_vif *vif;
 } __packed;
index 59018cc..41c990a 100644 (file)
 static enum hal_tcl_encap_type
 ath11k_dp_tx_get_encap_type(struct ath11k_vif *arvif, struct sk_buff *skb)
 {
-       /* TODO: Determine encap type based on vif_type and configuration */
+       struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
+
+       if (tx_info->control.flags & IEEE80211_TX_CTRL_HW_80211_ENCAP)
+               return HAL_TCL_ENCAP_TYPE_ETHERNET;
+
        return HAL_TCL_ENCAP_TYPE_NATIVE_WIFI;
 }
 
@@ -36,8 +40,11 @@ static void ath11k_dp_tx_encap_nwifi(struct sk_buff *skb)
 static u8 ath11k_dp_tx_get_tid(struct sk_buff *skb)
 {
        struct ieee80211_hdr *hdr = (void *)skb->data;
+       struct ath11k_skb_cb *cb = ATH11K_SKB_CB(skb);
 
-       if (!ieee80211_is_data_qos(hdr->frame_control))
+       if (cb->flags & ATH11K_SKB_HW_80211_ENCAP)
+               return skb->priority & IEEE80211_QOS_CTL_TID_MASK;
+       else if (!ieee80211_is_data_qos(hdr->frame_control))
                return HAL_DESC_REO_NON_QOS_TID;
        else
                return skb->priority & IEEE80211_QOS_CTL_TID_MASK;
@@ -86,7 +93,8 @@ int ath11k_dp_tx(struct ath11k *ar, struct ath11k_vif *arvif,
        if (test_bit(ATH11K_FLAG_CRASH_FLUSH, &ar->ab->dev_flags))
                return -ESHUTDOWN;
 
-       if (!ieee80211_is_data(hdr->frame_control))
+       if (!(info->control.flags & IEEE80211_TX_CTRL_HW_80211_ENCAP) &&
+           !ieee80211_is_data(hdr->frame_control))
                return -ENOTSUPP;
 
        pool_id = skb_get_queue_mapping(skb) & (ATH11K_HW_MAX_QUEUES - 1);
@@ -166,7 +174,10 @@ tcl_ring_sel:
                 *        skb_checksum_help() is needed
                 */
        case HAL_TCL_ENCAP_TYPE_ETHERNET:
+               /* no need to encap */
+               break;
        case HAL_TCL_ENCAP_TYPE_802_3:
+       default:
                /* TODO: Take care of other encap modes as well */
                ret = -EINVAL;
                goto fail_remove_idr;
index f33c6d7..5ffe558 100644 (file)
        .max_power              = 30, \
 }
 
+/* frame mode values are mapped as per enum ath11k_hw_txrx_mode */
+static unsigned int ath11k_frame_mode = ATH11K_HW_TXRX_NATIVE_WIFI;
+module_param_named(frame_mode, ath11k_frame_mode, uint, 0644);
+MODULE_PARM_DESC(frame_mode,
+                "Datapath frame mode (0: raw, 1: native wifi (default), 2: ethernet)");
+
 static const struct ieee80211_channel ath11k_2ghz_channels[] = {
        CHAN2G(1, 2412, 0),
        CHAN2G(2, 2417, 0),
@@ -3686,10 +3692,10 @@ static int __ath11k_set_antenna(struct ath11k *ar, u32 tx_ant, u32 rx_ant)
 
 int ath11k_mac_tx_mgmt_pending_free(int buf_id, void *skb, void *ctx)
 {
+       struct sk_buff *msdu = skb;
+       struct ieee80211_tx_info *info = IEEE80211_SKB_CB(msdu);
        struct ath11k *ar = ctx;
        struct ath11k_base *ab = ar->ab;
-       struct sk_buff *msdu = skb;
-       struct ieee80211_tx_info *info;
 
        spin_lock_bh(&ar->txmgmt_idr_lock);
        idr_remove(&ar->txmgmt_idr, buf_id);
@@ -3729,6 +3735,7 @@ static int ath11k_mac_mgmt_tx_wmi(struct ath11k *ar, struct ath11k_vif *arvif,
 {
        struct ath11k_base *ab = ar->ab;
        struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
+       struct ieee80211_tx_info *info;
        dma_addr_t paddr;
        int buf_id;
        int ret;
@@ -3740,11 +3747,14 @@ static int ath11k_mac_mgmt_tx_wmi(struct ath11k *ar, struct ath11k_vif *arvif,
        if (buf_id < 0)
                return -ENOSPC;
 
-       if ((ieee80211_is_action(hdr->frame_control) ||
-            ieee80211_is_deauth(hdr->frame_control) ||
-            ieee80211_is_disassoc(hdr->frame_control)) &&
-            ieee80211_has_protected(hdr->frame_control)) {
-               skb_put(skb, IEEE80211_CCMP_MIC_LEN);
+       info = IEEE80211_SKB_CB(skb);
+       if (!(info->control.flags & IEEE80211_TX_CTRL_HW_80211_ENCAP)) {
+               if ((ieee80211_is_action(hdr->frame_control) ||
+                    ieee80211_is_deauth(hdr->frame_control) ||
+                    ieee80211_is_disassoc(hdr->frame_control)) &&
+                    ieee80211_has_protected(hdr->frame_control)) {
+                       skb_put(skb, IEEE80211_CCMP_MIC_LEN);
+               }
        }
 
        paddr = dma_map_single(ab->dev, skb->data, skb->len, DMA_TO_DEVICE);
@@ -3856,6 +3866,7 @@ static void ath11k_mac_op_tx(struct ieee80211_hw *hw,
                             struct ieee80211_tx_control *control,
                             struct sk_buff *skb)
 {
+       struct ath11k_skb_cb *skb_cb = ATH11K_SKB_CB(skb);
        struct ath11k *ar = hw->priv;
        struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
        struct ieee80211_vif *vif = info->control.vif;
@@ -3864,7 +3875,9 @@ static void ath11k_mac_op_tx(struct ieee80211_hw *hw,
        bool is_prb_rsp;
        int ret;
 
-       if (ieee80211_is_mgmt(hdr->frame_control)) {
+       if (info->control.flags & IEEE80211_TX_CTRL_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);
                ret = ath11k_mac_mgmt_tx(ar, skb, is_prb_rsp);
                if (ret) {
@@ -4145,6 +4158,7 @@ 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;
@@ -4239,7 +4253,22 @@ static int ath11k_mac_op_add_interface(struct ieee80211_hw *hw,
        spin_unlock_bh(&ar->data_lock);
 
        param_id = WMI_VDEV_PARAM_TX_ENCAP_TYPE;
-       param_value = ATH11K_HW_TXRX_NATIVE_WIFI;
+       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) {
index ba05935..bce8fc2 100644 (file)
@@ -4568,6 +4568,9 @@ enum wmi_sta_ps_param_rx_wake_policy {
        WMI_STA_PS_RX_WAKE_POLICY_POLL_UAPSD = 1,
 };
 
+/* Do not change existing values! Used by ath11k_frame_mode parameter
+ * module parameter.
+ */
 enum ath11k_hw_txrx_mode {
        ATH11K_HW_TXRX_RAW = 0,
        ATH11K_HW_TXRX_NATIVE_WIFI = 1,