Commit e7f33e0c authored by John Crispin's avatar John Crispin Committed by Kalle Valo

ath11k: add tx hw 802.11 encapsulation offloading support

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: default avatarShashidhar Lakkavalli <slakkavalli@datto.com>
Signed-off-by: default avatarJohn Crispin <john@phrozen.org>
Signed-off-by: default avatarKalle Valo <kvalo@codeaurora.org>
Link: https://lore.kernel.org/r/20200430152814.18481-1-john@phrozen.org
parent 52f274b5
...@@ -60,9 +60,14 @@ static inline enum wme_ac ath11k_tid_to_ac(u32 tid) ...@@ -60,9 +60,14 @@ static inline enum wme_ac ath11k_tid_to_ac(u32 tid)
WME_AC_VO); WME_AC_VO);
} }
enum ath11k_skb_flags {
ATH11K_SKB_HW_80211_ENCAP = BIT(0),
};
struct ath11k_skb_cb { struct ath11k_skb_cb {
dma_addr_t paddr; dma_addr_t paddr;
u8 eid; u8 eid;
u8 flags;
struct ath11k *ar; struct ath11k *ar;
struct ieee80211_vif *vif; struct ieee80211_vif *vif;
} __packed; } __packed;
......
...@@ -12,7 +12,11 @@ ...@@ -12,7 +12,11 @@
static enum hal_tcl_encap_type static enum hal_tcl_encap_type
ath11k_dp_tx_get_encap_type(struct ath11k_vif *arvif, struct sk_buff *skb) 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; return HAL_TCL_ENCAP_TYPE_NATIVE_WIFI;
} }
...@@ -36,8 +40,11 @@ static void ath11k_dp_tx_encap_nwifi(struct sk_buff *skb) ...@@ -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) static u8 ath11k_dp_tx_get_tid(struct sk_buff *skb)
{ {
struct ieee80211_hdr *hdr = (void *)skb->data; 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; return HAL_DESC_REO_NON_QOS_TID;
else else
return skb->priority & IEEE80211_QOS_CTL_TID_MASK; return skb->priority & IEEE80211_QOS_CTL_TID_MASK;
...@@ -86,7 +93,8 @@ int ath11k_dp_tx(struct ath11k *ar, struct ath11k_vif *arvif, ...@@ -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)) if (test_bit(ATH11K_FLAG_CRASH_FLUSH, &ar->ab->dev_flags))
return -ESHUTDOWN; 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; return -ENOTSUPP;
pool_id = skb_get_queue_mapping(skb) & (ATH11K_HW_MAX_QUEUES - 1); pool_id = skb_get_queue_mapping(skb) & (ATH11K_HW_MAX_QUEUES - 1);
...@@ -166,7 +174,10 @@ int ath11k_dp_tx(struct ath11k *ar, struct ath11k_vif *arvif, ...@@ -166,7 +174,10 @@ int ath11k_dp_tx(struct ath11k *ar, struct ath11k_vif *arvif,
* skb_checksum_help() is needed * skb_checksum_help() is needed
*/ */
case HAL_TCL_ENCAP_TYPE_ETHERNET: case HAL_TCL_ENCAP_TYPE_ETHERNET:
/* no need to encap */
break;
case HAL_TCL_ENCAP_TYPE_802_3: case HAL_TCL_ENCAP_TYPE_802_3:
default:
/* TODO: Take care of other encap modes as well */ /* TODO: Take care of other encap modes as well */
ret = -EINVAL; ret = -EINVAL;
goto fail_remove_idr; goto fail_remove_idr;
......
...@@ -33,6 +33,12 @@ ...@@ -33,6 +33,12 @@
.max_power = 30, \ .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[] = { static const struct ieee80211_channel ath11k_2ghz_channels[] = {
CHAN2G(1, 2412, 0), CHAN2G(1, 2412, 0),
CHAN2G(2, 2417, 0), CHAN2G(2, 2417, 0),
...@@ -3686,10 +3692,10 @@ static int __ath11k_set_antenna(struct ath11k *ar, u32 tx_ant, u32 rx_ant) ...@@ -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) 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 *ar = ctx;
struct ath11k_base *ab = ar->ab; struct ath11k_base *ab = ar->ab;
struct sk_buff *msdu = skb;
struct ieee80211_tx_info *info;
spin_lock_bh(&ar->txmgmt_idr_lock); spin_lock_bh(&ar->txmgmt_idr_lock);
idr_remove(&ar->txmgmt_idr, buf_id); 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, ...@@ -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 ath11k_base *ab = ar->ab;
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
struct ieee80211_tx_info *info;
dma_addr_t paddr; dma_addr_t paddr;
int buf_id; int buf_id;
int ret; int ret;
...@@ -3740,11 +3747,14 @@ static int ath11k_mac_mgmt_tx_wmi(struct ath11k *ar, struct ath11k_vif *arvif, ...@@ -3740,11 +3747,14 @@ static int ath11k_mac_mgmt_tx_wmi(struct ath11k *ar, struct ath11k_vif *arvif,
if (buf_id < 0) if (buf_id < 0)
return -ENOSPC; return -ENOSPC;
if ((ieee80211_is_action(hdr->frame_control) || info = IEEE80211_SKB_CB(skb);
ieee80211_is_deauth(hdr->frame_control) || if (!(info->control.flags & IEEE80211_TX_CTRL_HW_80211_ENCAP)) {
ieee80211_is_disassoc(hdr->frame_control)) && if ((ieee80211_is_action(hdr->frame_control) ||
ieee80211_has_protected(hdr->frame_control)) { ieee80211_is_deauth(hdr->frame_control) ||
skb_put(skb, IEEE80211_CCMP_MIC_LEN); 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); 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, ...@@ -3856,6 +3866,7 @@ static void ath11k_mac_op_tx(struct ieee80211_hw *hw,
struct ieee80211_tx_control *control, struct ieee80211_tx_control *control,
struct sk_buff *skb) struct sk_buff *skb)
{ {
struct ath11k_skb_cb *skb_cb = ATH11K_SKB_CB(skb);
struct ath11k *ar = hw->priv; struct ath11k *ar = hw->priv;
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
struct ieee80211_vif *vif = info->control.vif; struct ieee80211_vif *vif = info->control.vif;
...@@ -3864,7 +3875,9 @@ static void ath11k_mac_op_tx(struct ieee80211_hw *hw, ...@@ -3864,7 +3875,9 @@ static void ath11k_mac_op_tx(struct ieee80211_hw *hw,
bool is_prb_rsp; bool is_prb_rsp;
int ret; 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); is_prb_rsp = ieee80211_is_probe_resp(hdr->frame_control);
ret = ath11k_mac_mgmt_tx(ar, skb, is_prb_rsp); ret = ath11k_mac_mgmt_tx(ar, skb, is_prb_rsp);
if (ret) { if (ret) {
...@@ -4145,6 +4158,7 @@ static int ath11k_mac_op_add_interface(struct ieee80211_hw *hw, ...@@ -4145,6 +4158,7 @@ static int ath11k_mac_op_add_interface(struct ieee80211_hw *hw,
struct vdev_create_params vdev_param = {0}; struct vdev_create_params vdev_param = {0};
struct peer_create_params peer_param; struct peer_create_params peer_param;
u32 param_id, param_value; u32 param_id, param_value;
int hw_encap = 0;
u16 nss; u16 nss;
int i; int i;
int ret; int ret;
...@@ -4239,7 +4253,22 @@ static int ath11k_mac_op_add_interface(struct ieee80211_hw *hw, ...@@ -4239,7 +4253,22 @@ static int ath11k_mac_op_add_interface(struct ieee80211_hw *hw,
spin_unlock_bh(&ar->data_lock); spin_unlock_bh(&ar->data_lock);
param_id = WMI_VDEV_PARAM_TX_ENCAP_TYPE; 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, ret = ath11k_wmi_vdev_set_param_cmd(ar, arvif->vdev_id,
param_id, param_value); param_id, param_value);
if (ret) { if (ret) {
......
...@@ -4568,6 +4568,9 @@ enum wmi_sta_ps_param_rx_wake_policy { ...@@ -4568,6 +4568,9 @@ enum wmi_sta_ps_param_rx_wake_policy {
WMI_STA_PS_RX_WAKE_POLICY_POLL_UAPSD = 1, 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 { enum ath11k_hw_txrx_mode {
ATH11K_HW_TXRX_RAW = 0, ATH11K_HW_TXRX_RAW = 0,
ATH11K_HW_TXRX_NATIVE_WIFI = 1, ATH11K_HW_TXRX_NATIVE_WIFI = 1,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment