Commit 5567d4d9 authored by Alex Elder's avatar Alex Elder Committed by David S. Miller

net: ipa: add support for inline checksum offload

Starting with IPA v4.5, IP payload checksum offload is implemented
differently.

Prior to v4.5, the IPA hardware appends an rmnet_map_dl_csum_trailer
structure to each packet if checksum offload is enabled in the
download direction (modem->AP).  In the upload direction (AP->modem)
a rmnet_map_ul_csum_header structure is prepended before each sent
packet.

Starting with IPA v4.5, checksum offload is implemented using a
single new rmnet_map_v5_csum_header structure which sits between
the QMAP header and the packet data.  The same header structure
is used in both directions.

The new header contains a header type (CSUM_OFFLOAD); a checksum
flag; and a flag indicating whether any other headers follow this
one.  The checksum flag indicates whether the hardware should
compute (and insert) the checksum on a sent packet.  On a received
packet the checksum flag indicates whether the hardware confirms the
checksum value in the payload is correct.
Signed-off-by: default avatarAlex Elder <elder@linaro.org>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent fcd1a530
...@@ -457,28 +457,34 @@ int ipa_endpoint_modem_exception_reset_all(struct ipa *ipa) ...@@ -457,28 +457,34 @@ int ipa_endpoint_modem_exception_reset_all(struct ipa *ipa)
static void ipa_endpoint_init_cfg(struct ipa_endpoint *endpoint) static void ipa_endpoint_init_cfg(struct ipa_endpoint *endpoint)
{ {
u32 offset = IPA_REG_ENDP_INIT_CFG_N_OFFSET(endpoint->endpoint_id); u32 offset = IPA_REG_ENDP_INIT_CFG_N_OFFSET(endpoint->endpoint_id);
enum ipa_cs_offload_en enabled;
u32 val = 0; u32 val = 0;
/* FRAG_OFFLOAD_EN is 0 */ /* FRAG_OFFLOAD_EN is 0 */
if (endpoint->data->checksum) { if (endpoint->data->checksum) {
enum ipa_version version = endpoint->ipa->version;
if (endpoint->toward_ipa) { if (endpoint->toward_ipa) {
u32 checksum_offset; u32 checksum_offset;
val |= u32_encode_bits(IPA_CS_OFFLOAD_UL,
CS_OFFLOAD_EN_FMASK);
/* Checksum header offset is in 4-byte units */ /* Checksum header offset is in 4-byte units */
checksum_offset = sizeof(struct rmnet_map_header); checksum_offset = sizeof(struct rmnet_map_header);
checksum_offset /= sizeof(u32); checksum_offset /= sizeof(u32);
val |= u32_encode_bits(checksum_offset, val |= u32_encode_bits(checksum_offset,
CS_METADATA_HDR_OFFSET_FMASK); CS_METADATA_HDR_OFFSET_FMASK);
enabled = version < IPA_VERSION_4_5
? IPA_CS_OFFLOAD_UL
: IPA_CS_OFFLOAD_INLINE;
} else { } else {
val |= u32_encode_bits(IPA_CS_OFFLOAD_DL, enabled = version < IPA_VERSION_4_5
CS_OFFLOAD_EN_FMASK); ? IPA_CS_OFFLOAD_DL
: IPA_CS_OFFLOAD_INLINE;
} }
} else { } else {
val |= u32_encode_bits(IPA_CS_OFFLOAD_NONE, enabled = IPA_CS_OFFLOAD_NONE;
CS_OFFLOAD_EN_FMASK);
} }
val |= u32_encode_bits(enabled, CS_OFFLOAD_EN_FMASK);
/* CS_GEN_QMB_MASTER_SEL is 0 */ /* CS_GEN_QMB_MASTER_SEL is 0 */
iowrite32(val, endpoint->ipa->reg_virt + offset); iowrite32(val, endpoint->ipa->reg_virt + offset);
...@@ -498,6 +504,27 @@ static void ipa_endpoint_init_nat(struct ipa_endpoint *endpoint) ...@@ -498,6 +504,27 @@ static void ipa_endpoint_init_nat(struct ipa_endpoint *endpoint)
iowrite32(val, endpoint->ipa->reg_virt + offset); iowrite32(val, endpoint->ipa->reg_virt + offset);
} }
static u32
ipa_qmap_header_size(enum ipa_version version, struct ipa_endpoint *endpoint)
{
u32 header_size = sizeof(struct rmnet_map_header);
/* Without checksum offload, we just have the MAP header */
if (!endpoint->data->checksum)
return header_size;
if (version < IPA_VERSION_4_5) {
/* Checksum header inserted for AP TX endpoints only */
if (endpoint->toward_ipa)
header_size += sizeof(struct rmnet_map_ul_csum_header);
} else {
/* Checksum header is used in both directions */
header_size += sizeof(struct rmnet_map_v5_csum_header);
}
return header_size;
}
/** /**
* ipa_endpoint_init_hdr() - Initialize HDR endpoint configuration register * ipa_endpoint_init_hdr() - Initialize HDR endpoint configuration register
* @endpoint: Endpoint pointer * @endpoint: Endpoint pointer
...@@ -526,13 +553,11 @@ static void ipa_endpoint_init_hdr(struct ipa_endpoint *endpoint) ...@@ -526,13 +553,11 @@ static void ipa_endpoint_init_hdr(struct ipa_endpoint *endpoint)
u32 val = 0; u32 val = 0;
if (endpoint->data->qmap) { if (endpoint->data->qmap) {
size_t header_size = sizeof(struct rmnet_map_header);
enum ipa_version version = ipa->version; enum ipa_version version = ipa->version;
size_t header_size;
/* We might supply a checksum header after the QMAP header */ header_size = ipa_qmap_header_size(version, endpoint);
if (endpoint->toward_ipa && endpoint->data->checksum) val = ipa_header_size_encoded(version, header_size);
header_size += sizeof(struct rmnet_map_ul_csum_header);
val |= ipa_header_size_encoded(version, header_size);
/* Define how to fill fields in a received QMAP header */ /* Define how to fill fields in a received QMAP header */
if (!endpoint->toward_ipa) { if (!endpoint->toward_ipa) {
......
...@@ -368,6 +368,7 @@ enum ipa_cs_offload_en { ...@@ -368,6 +368,7 @@ enum ipa_cs_offload_en {
IPA_CS_OFFLOAD_NONE = 0x0, IPA_CS_OFFLOAD_NONE = 0x0,
IPA_CS_OFFLOAD_UL = 0x1, /* Before IPA v4.5 (TX) */ IPA_CS_OFFLOAD_UL = 0x1, /* Before IPA v4.5 (TX) */
IPA_CS_OFFLOAD_DL = 0x2, /* Before IPA v4.5 (RX) */ IPA_CS_OFFLOAD_DL = 0x2, /* Before IPA v4.5 (RX) */
IPA_CS_OFFLOAD_INLINE = 0x1, /* IPA v4.5 (TX and RX) */
}; };
/* Valid only for TX (IPA consumer) endpoints */ /* Valid only for TX (IPA consumer) endpoints */
......
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