Commit 59ca9572 authored by Johannes Berg's avatar Johannes Berg Committed by Luca Coelho

iwlwifi: mvm: use CHECKSUM_COMPLETE

On newer hardware, we have the full checksum, so use it to report
CHECKSUM_COMPLETE and avoid the protocol specific hardware parsing.

Note that the hardware already parses/removes the SNAP header, so
we actually literally get what we need to report to the stack, as
we're expected to checksum everything after the L2 header (which
is translated/added by mac80211).
Signed-off-by: default avatarJohannes Berg <johannes.berg@intel.com>
Signed-off-by: default avatarLuca Coelho <luciano.coelho@intel.com>
Link: https://lore.kernel.org/r/iwlwifi.20200926002540.869e829c815d.I70f374865b0acafc675a8d7959912eeaeb595acf@changeidSigned-off-by: default avatarLuca Coelho <luciano.coelho@intel.com>
parent cfa5d0ca
...@@ -560,7 +560,11 @@ struct iwl_rx_mpdu_desc_v3 { ...@@ -560,7 +560,11 @@ struct iwl_rx_mpdu_desc_v3 {
/** /**
* @raw_xsum: raw xsum value * @raw_xsum: raw xsum value
*/ */
__le32 raw_xsum; __be16 raw_xsum;
/**
* @reserved_xsum: reserved high bits in the raw checksum
*/
__le16 reserved_xsum;
/* DW11 */ /* DW11 */
/** /**
* @rate_n_flags: RX rate/flags encoding * @rate_n_flags: RX rate/flags encoding
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
* Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH
* Copyright(c) 2015 - 2017 Intel Deutschland GmbH * Copyright(c) 2015 - 2017 Intel Deutschland GmbH
* Copyright(c) 2018 - 2019 Intel Corporation * Copyright(c) 2018 - 2020 Intel Corporation
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of version 2 of the GNU General Public License as * it under the terms of version 2 of the GNU General Public License as
...@@ -31,7 +31,7 @@ ...@@ -31,7 +31,7 @@
* Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
* Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH
* Copyright(c) 2015 - 2017 Intel Deutschland GmbH * Copyright(c) 2015 - 2017 Intel Deutschland GmbH
* Copyright(c) 2018 - 2019 Intel Corporation * Copyright(c) 2018 - 2020 Intel Corporation
* All rights reserved. * All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without
...@@ -221,6 +221,31 @@ static int iwl_mvm_create_skb(struct iwl_mvm *mvm, struct sk_buff *skb, ...@@ -221,6 +221,31 @@ static int iwl_mvm_create_skb(struct iwl_mvm *mvm, struct sk_buff *skb,
skb_put_data(skb, hdr, hdrlen); skb_put_data(skb, hdr, hdrlen);
skb_put_data(skb, (u8 *)hdr + hdrlen + pad_len, headlen - hdrlen); skb_put_data(skb, (u8 *)hdr + hdrlen + pad_len, headlen - hdrlen);
/*
* If we did CHECKSUM_COMPLETE, the hardware only does it right for
* certain cases and starts the checksum after the SNAP. Check if
* this is the case - it's easier to just bail out to CHECKSUM_NONE
* in the cases the hardware didn't handle, since it's rare to see
* such packets, even though the hardware did calculate the checksum
* in this case, just starting after the MAC header instead.
*/
if (skb->ip_summed == CHECKSUM_COMPLETE) {
struct {
u8 hdr[6];
__be16 type;
} __packed *shdr = (void *)((u8 *)hdr + hdrlen + pad_len);
if (unlikely(headlen - hdrlen < sizeof(*shdr) ||
!ether_addr_equal(shdr->hdr, rfc1042_header) ||
(shdr->type != htons(ETH_P_IP) &&
shdr->type != htons(ETH_P_ARP) &&
shdr->type != htons(ETH_P_IPV6) &&
shdr->type != htons(ETH_P_8021Q) &&
shdr->type != htons(ETH_P_PAE) &&
shdr->type != htons(ETH_P_TDLS))))
skb->ip_summed = CHECKSUM_NONE;
}
fraglen = len - headlen; fraglen = len - headlen;
if (fraglen) { if (fraglen) {
...@@ -393,22 +418,36 @@ static int iwl_mvm_rx_crypto(struct iwl_mvm *mvm, struct ieee80211_hdr *hdr, ...@@ -393,22 +418,36 @@ static int iwl_mvm_rx_crypto(struct iwl_mvm *mvm, struct ieee80211_hdr *hdr,
return 0; return 0;
} }
static void iwl_mvm_rx_csum(struct ieee80211_sta *sta, static void iwl_mvm_rx_csum(struct iwl_mvm *mvm,
struct ieee80211_sta *sta,
struct sk_buff *skb, struct sk_buff *skb,
struct iwl_rx_mpdu_desc *desc) struct iwl_rx_packet *pkt)
{ {
struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta); struct iwl_rx_mpdu_desc *desc = (void *)pkt->data;
struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(mvmsta->vif);
u16 flags = le16_to_cpu(desc->l3l4_flags); if (mvm->trans->trans_cfg->device_family >= IWL_DEVICE_FAMILY_AX210) {
u8 l3_prot = (u8)((flags & IWL_RX_L3L4_L3_PROTO_MASK) >> if (pkt->len_n_flags & cpu_to_le32(FH_RSCSR_RPA_EN)) {
IWL_RX_L3_PROTO_POS); u16 hwsum = be16_to_cpu(desc->v3.raw_xsum);
if (mvmvif->features & NETIF_F_RXCSUM && skb->ip_summed = CHECKSUM_COMPLETE;
flags & IWL_RX_L3L4_TCP_UDP_CSUM_OK && skb->csum = csum_unfold(~(__force __sum16)hwsum);
(flags & IWL_RX_L3L4_IP_HDR_CSUM_OK || }
l3_prot == IWL_RX_L3_TYPE_IPV6 || } else {
l3_prot == IWL_RX_L3_TYPE_IPV6_FRAG)) struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta);
skb->ip_summed = CHECKSUM_UNNECESSARY; struct iwl_mvm_vif *mvmvif;
u16 flags = le16_to_cpu(desc->l3l4_flags);
u8 l3_prot = (u8)((flags & IWL_RX_L3L4_L3_PROTO_MASK) >>
IWL_RX_L3_PROTO_POS);
mvmvif = iwl_mvm_vif_from_mac80211(mvmsta->vif);
if (mvmvif->features & NETIF_F_RXCSUM &&
flags & IWL_RX_L3L4_TCP_UDP_CSUM_OK &&
(flags & IWL_RX_L3L4_IP_HDR_CSUM_OK ||
l3_prot == IWL_RX_L3_TYPE_IPV6 ||
l3_prot == IWL_RX_L3_TYPE_IPV6_FRAG))
skb->ip_summed = CHECKSUM_UNNECESSARY;
}
} }
/* /*
...@@ -1796,7 +1835,7 @@ void iwl_mvm_rx_mpdu_mq(struct iwl_mvm *mvm, struct napi_struct *napi, ...@@ -1796,7 +1835,7 @@ void iwl_mvm_rx_mpdu_mq(struct iwl_mvm *mvm, struct napi_struct *napi,
} }
if (ieee80211_is_data(hdr->frame_control)) if (ieee80211_is_data(hdr->frame_control))
iwl_mvm_rx_csum(sta, skb, desc); iwl_mvm_rx_csum(mvm, sta, skb, pkt);
if (iwl_mvm_is_dup(sta, queue, rx_status, hdr, desc)) { if (iwl_mvm_is_dup(sta, queue, rx_status, hdr, desc)) {
kfree_skb(skb); kfree_skb(skb);
......
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