From 63a560b5289a0f9d66d099fb093c20b0abe01027 Mon Sep 17 00:00:00 2001 From: Alex Elder Date: Wed, 25 Jan 2023 14:45:38 -0600 Subject: [PATCH 1/8] net: ipa: refactor status buffer parsing The packet length encoded in an IPA packet status buffer is computed more than once in ipa_endpoint_status_parse(). It is also checked again in ipa_endpoint_status_skip(), which that function calls. Compute the length once, and use that computed value later rather than recomputing it. Check for it being zero in the parse function rather than in ipa_endpoint_status_skip(). Signed-off-by: Alex Elder Signed-off-by: David S. Miller --- drivers/net/ipa/ipa_endpoint.c | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/drivers/net/ipa/ipa_endpoint.c b/drivers/net/ipa/ipa_endpoint.c index 136932464261..3756ce5f3f31 100644 --- a/drivers/net/ipa/ipa_endpoint.c +++ b/drivers/net/ipa/ipa_endpoint.c @@ -1325,8 +1325,7 @@ static bool ipa_endpoint_status_skip(struct ipa_endpoint *endpoint, if (!ipa_status_format_packet(status->opcode)) return true; - if (!status->pkt_len) - return true; + endpoint_id = u8_get_bits(status->endp_dst_idx, IPA_STATUS_DST_IDX_FMASK); if (endpoint_id != endpoint->endpoint_id) @@ -1394,6 +1393,7 @@ static void ipa_endpoint_status_parse(struct ipa_endpoint *endpoint, while (resid) { const struct ipa_status *status = data; + u32 length; u32 align; u32 len; @@ -1405,7 +1405,8 @@ static void ipa_endpoint_status_parse(struct ipa_endpoint *endpoint, } /* Skip over status packets that lack packet data */ - if (ipa_endpoint_status_skip(endpoint, status)) { + length = le16_to_cpu(status->pkt_len); + if (!length || ipa_endpoint_status_skip(endpoint, status)) { data += sizeof(*status); resid -= sizeof(*status); continue; @@ -1418,19 +1419,16 @@ static void ipa_endpoint_status_parse(struct ipa_endpoint *endpoint, * computed checksum information will be appended. */ align = endpoint->config.rx.pad_align ? : 1; - len = le16_to_cpu(status->pkt_len); - len = sizeof(*status) + ALIGN(len, align); + len = sizeof(*status) + ALIGN(length, align); if (endpoint->config.checksum) len += sizeof(struct rmnet_map_dl_csum_trailer); if (!ipa_endpoint_status_drop(endpoint, status)) { void *data2; u32 extra; - u32 len2; /* Client receives only packet data (no status) */ data2 = data + sizeof(*status); - len2 = le16_to_cpu(status->pkt_len); /* Have the true size reflect the extra unused space in * the original receive buffer. Distribute the "cost" @@ -1438,7 +1436,7 @@ static void ipa_endpoint_status_parse(struct ipa_endpoint *endpoint, * buffer. */ extra = DIV_ROUND_CLOSEST(unused * len, total_len); - ipa_endpoint_skb_copy(endpoint, data2, len2, extra); + ipa_endpoint_skb_copy(endpoint, data2, length, extra); } /* Consume status and the full packet it describes */ From b8dc7d0eea5a7709bb534f1b3ca70d2d7de0b42c Mon Sep 17 00:00:00 2001 From: Alex Elder Date: Wed, 25 Jan 2023 14:45:39 -0600 Subject: [PATCH 2/8] net: ipa: stop using sizeof(status) The IPA packet status structure changes in IPA v5.0 in ways that are difficult to represent cleanly. As a small step toward redefining it as a parsed block of data, use a constant to define its size, rather than the size of the IPA status structure type. Signed-off-by: Alex Elder Signed-off-by: David S. Miller --- drivers/net/ipa/ipa_endpoint.c | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/drivers/net/ipa/ipa_endpoint.c b/drivers/net/ipa/ipa_endpoint.c index 3756ce5f3f31..dd4b2b073aae 100644 --- a/drivers/net/ipa/ipa_endpoint.c +++ b/drivers/net/ipa/ipa_endpoint.c @@ -70,6 +70,9 @@ struct ipa_status { #define IPA_STATUS_FLAGS1_RT_RULE_ID_FMASK GENMASK(31, 22) #define IPA_STATUS_FLAGS2_TAG_FMASK GENMASK_ULL(63, 16) +/* Size in bytes of an IPA packet status structure */ +#define IPA_STATUS_SIZE sizeof(__le32[4]) + /* Compute the aggregation size value to use for a given buffer size */ static u32 ipa_aggr_size_kb(u32 rx_buffer_size, bool aggr_hard_limit) { @@ -1397,18 +1400,18 @@ static void ipa_endpoint_status_parse(struct ipa_endpoint *endpoint, u32 align; u32 len; - if (resid < sizeof(*status)) { + if (resid < IPA_STATUS_SIZE) { dev_err(&endpoint->ipa->pdev->dev, "short message (%u bytes < %zu byte status)\n", - resid, sizeof(*status)); + resid, IPA_STATUS_SIZE); break; } /* Skip over status packets that lack packet data */ length = le16_to_cpu(status->pkt_len); if (!length || ipa_endpoint_status_skip(endpoint, status)) { - data += sizeof(*status); - resid -= sizeof(*status); + data += IPA_STATUS_SIZE; + resid -= IPA_STATUS_SIZE; continue; } @@ -1419,7 +1422,7 @@ static void ipa_endpoint_status_parse(struct ipa_endpoint *endpoint, * computed checksum information will be appended. */ align = endpoint->config.rx.pad_align ? : 1; - len = sizeof(*status) + ALIGN(length, align); + len = IPA_STATUS_SIZE + ALIGN(length, align); if (endpoint->config.checksum) len += sizeof(struct rmnet_map_dl_csum_trailer); @@ -1428,7 +1431,7 @@ static void ipa_endpoint_status_parse(struct ipa_endpoint *endpoint, u32 extra; /* Client receives only packet data (no status) */ - data2 = data + sizeof(*status); + data2 = data + IPA_STATUS_SIZE; /* Have the true size reflect the extra unused space in * the original receive buffer. Distribute the "cost" From 8e71708bb25e8f8a33d1bc90e651d73988b15dde Mon Sep 17 00:00:00 2001 From: Alex Elder Date: Wed, 25 Jan 2023 14:45:40 -0600 Subject: [PATCH 3/8] net: ipa: define all IPA status mask bits There is a 16 bit status mask defined in the IPA packet status structure, of which only one (TAG_VALID) is currently used. Define all other IPA status mask values in an enumerated type whose numeric values are bit mask values (in CPU byte order) in the status mask. Use the TAG_VALID value from that type rather than defining a separate field mask. Signed-off-by: Alex Elder Signed-off-by: David S. Miller --- drivers/net/ipa/ipa_endpoint.c | 25 ++++++++++++++++++++++--- 1 file changed, 22 insertions(+), 3 deletions(-) diff --git a/drivers/net/ipa/ipa_endpoint.c b/drivers/net/ipa/ipa_endpoint.c index dd4b2b073aae..5cf3ac2b5c85 100644 --- a/drivers/net/ipa/ipa_endpoint.c +++ b/drivers/net/ipa/ipa_endpoint.c @@ -48,11 +48,31 @@ enum ipa_status_exception { IPA_STATUS_EXCEPTION_DEAGGR = 0x01, }; +/** enum ipa_status_mask - IPA status mask field bitmask hardware values */ +enum ipa_status_mask { + IPA_STATUS_MASK_FRAG_PROCESS = BIT(0), + IPA_STATUS_MASK_FILT_PROCESS = BIT(1), + IPA_STATUS_MASK_NAT_PROCESS = BIT(2), + IPA_STATUS_MASK_ROUTE_PROCESS = BIT(3), + IPA_STATUS_MASK_TAG_VALID = BIT(4), + IPA_STATUS_MASK_FRAGMENT = BIT(5), + IPA_STATUS_MASK_FIRST_FRAGMENT = BIT(6), + IPA_STATUS_MASK_V4 = BIT(7), + IPA_STATUS_MASK_CKSUM_PROCESS = BIT(8), + IPA_STATUS_MASK_AGGR_PROCESS = BIT(9), + IPA_STATUS_MASK_DEST_EOT = BIT(10), + IPA_STATUS_MASK_DEAGGR_PROCESS = BIT(11), + IPA_STATUS_MASK_DEAGG_FIRST = BIT(12), + IPA_STATUS_MASK_SRC_EOT = BIT(13), + IPA_STATUS_MASK_PREV_EOT = BIT(14), + IPA_STATUS_MASK_BYTE_LIMIT = BIT(15), +}; + /* Status element provided by hardware */ struct ipa_status { u8 opcode; /* enum ipa_status_opcode */ u8 exception; /* enum ipa_status_exception */ - __le16 mask; + __le16 mask; /* enum ipa_status_bit (bitmask) */ __le16 pkt_len; u8 endp_src_idx; u8 endp_dst_idx; @@ -64,7 +84,6 @@ struct ipa_status { }; /* Field masks for struct ipa_status structure fields */ -#define IPA_STATUS_MASK_TAG_VALID_FMASK GENMASK(4, 4) #define IPA_STATUS_SRC_IDX_FMASK GENMASK(4, 0) #define IPA_STATUS_DST_IDX_FMASK GENMASK(4, 0) #define IPA_STATUS_FLAGS1_RT_RULE_ID_FMASK GENMASK(31, 22) @@ -1344,7 +1363,7 @@ static bool ipa_endpoint_status_tag(struct ipa_endpoint *endpoint, struct ipa *ipa = endpoint->ipa; u32 endpoint_id; - if (!le16_get_bits(status->mask, IPA_STATUS_MASK_TAG_VALID_FMASK)) + if (!le16_get_bits(status->mask, IPA_STATUS_MASK_TAG_VALID)) return false; /* No valid tag */ /* The status contains a valid tag. We know the packet was sent to From cbea4761173dd962c7d057b580f991d3e713039a Mon Sep 17 00:00:00 2001 From: Alex Elder Date: Wed, 25 Jan 2023 14:45:41 -0600 Subject: [PATCH 4/8] net: ipa: rename the NAT enumerated type Rename the ipa_nat_en enumerated type to be ipa_nat_type, and rename its symbols accordingly. Add a comment indicating those values are also used in the IPA status nat_type field. Signed-off-by: Alex Elder Signed-off-by: David S. Miller --- drivers/net/ipa/ipa_endpoint.c | 4 +++- drivers/net/ipa/ipa_reg.h | 10 +++++----- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/drivers/net/ipa/ipa_endpoint.c b/drivers/net/ipa/ipa_endpoint.c index 5cf3ac2b5c85..178934f131be 100644 --- a/drivers/net/ipa/ipa_endpoint.c +++ b/drivers/net/ipa/ipa_endpoint.c @@ -68,6 +68,8 @@ enum ipa_status_mask { IPA_STATUS_MASK_BYTE_LIMIT = BIT(15), }; +/** The IPA status nat_type field uses enum ipa_nat_type hardware values */ + /* Status element provided by hardware */ struct ipa_status { u8 opcode; /* enum ipa_status_opcode */ @@ -570,7 +572,7 @@ static void ipa_endpoint_init_nat(struct ipa_endpoint *endpoint) return; reg = ipa_reg(ipa, ENDP_INIT_NAT); - val = ipa_reg_encode(reg, NAT_EN, IPA_NAT_BYPASS); + val = ipa_reg_encode(reg, NAT_EN, IPA_NAT_TYPE_BYPASS); iowrite32(val, ipa->reg_virt + ipa_reg_n_offset(reg, endpoint_id)); } diff --git a/drivers/net/ipa/ipa_reg.h b/drivers/net/ipa/ipa_reg.h index ff64b19a4df8..b1a3c2c7e167 100644 --- a/drivers/net/ipa/ipa_reg.h +++ b/drivers/net/ipa/ipa_reg.h @@ -382,11 +382,11 @@ enum ipa_reg_endp_init_nat_field_id { NAT_EN, }; -/** enum ipa_nat_en - ENDP_INIT_NAT register NAT_EN field value */ -enum ipa_nat_en { - IPA_NAT_BYPASS = 0x0, - IPA_NAT_SRC = 0x1, - IPA_NAT_DST = 0x2, +/** enum ipa_nat_type - ENDP_INIT_NAT register NAT_EN field value */ +enum ipa_nat_type { + IPA_NAT_TYPE_BYPASS = 0, + IPA_NAT_TYPE_SRC = 1, + IPA_NAT_TYPE_DST = 2, }; /* ENDP_INIT_HDR register */ From ec4c24f6a51104579bf54fa3a90df9fd5e8152d1 Mon Sep 17 00:00:00 2001 From: Alex Elder Date: Wed, 25 Jan 2023 14:45:42 -0600 Subject: [PATCH 5/8] net: ipa: define remaining IPA status field values Define the remaining values for opcode and exception fields in the IPA packet status structure. Most of these values are powers-of-2, suggesting they are meant to be used as bitmasks, but that is not the case. Add comments to be clear about this, and express the values in decimal format. Signed-off-by: Alex Elder Signed-off-by: David S. Miller --- drivers/net/ipa/ipa_endpoint.c | 31 ++++++++++++++++++++++--------- 1 file changed, 22 insertions(+), 9 deletions(-) diff --git a/drivers/net/ipa/ipa_endpoint.c b/drivers/net/ipa/ipa_endpoint.c index 178934f131be..ee3c29b1efea 100644 --- a/drivers/net/ipa/ipa_endpoint.c +++ b/drivers/net/ipa/ipa_endpoint.c @@ -34,18 +34,31 @@ #define IPA_ENDPOINT_RESET_AGGR_RETRY_MAX 3 -/** enum ipa_status_opcode - status element opcode hardware values */ -enum ipa_status_opcode { - IPA_STATUS_OPCODE_PACKET = 0x01, - IPA_STATUS_OPCODE_DROPPED_PACKET = 0x04, - IPA_STATUS_OPCODE_SUSPENDED_PACKET = 0x08, - IPA_STATUS_OPCODE_PACKET_2ND_PASS = 0x40, +/** enum ipa_status_opcode - IPA status opcode field hardware values */ +enum ipa_status_opcode { /* *Not* a bitmask */ + IPA_STATUS_OPCODE_PACKET = 1, + IPA_STATUS_OPCODE_NEW_RULE_PACKET = 2, + IPA_STATUS_OPCODE_DROPPED_PACKET = 4, + IPA_STATUS_OPCODE_SUSPENDED_PACKET = 8, + IPA_STATUS_OPCODE_LOG = 16, + IPA_STATUS_OPCODE_DCMP = 32, + IPA_STATUS_OPCODE_PACKET_2ND_PASS = 64, }; -/** enum ipa_status_exception - status element exception type */ -enum ipa_status_exception { +/** enum ipa_status_exception - IPA status exception field hardware values */ +enum ipa_status_exception { /* *Not* a bitmask */ /* 0 means no exception */ - IPA_STATUS_EXCEPTION_DEAGGR = 0x01, + IPA_STATUS_EXCEPTION_DEAGGR = 1, + IPA_STATUS_EXCEPTION_IPTYPE = 4, + IPA_STATUS_EXCEPTION_PACKET_LENGTH = 8, + IPA_STATUS_EXCEPTION_FRAG_RULE_MISS = 16, + IPA_STATUS_EXCEPTION_SW_FILTER = 32, + IPA_STATUS_EXCEPTION_NAT = 64, /* IPv4 */ + IPA_STATUS_EXCEPTION_IPV6_CONN_TRACK = 64, /* IPv6 */ + IPA_STATUS_EXCEPTION_UC = 128, + IPA_STATUS_EXCEPTION_INVALID_ENDPOINT = 129, + IPA_STATUS_EXCEPTION_HEADER_INSERT = 136, + IPA_STATUS_EXCEPTION_CHEKCSUM = 229, }; /** enum ipa_status_mask - IPA status mask field bitmask hardware values */ From 02c5077439fc7d4cd885add2d4e2d3e678b23e21 Mon Sep 17 00:00:00 2001 From: Alex Elder Date: Wed, 25 Jan 2023 14:45:43 -0600 Subject: [PATCH 6/8] net: ipa: IPA status preparatory cleanups The next patch reworks how the IPA packet status structure is interpreted. This patch does some preparatory work, to make it easier to see the effect of that change: - Change a few functions that access fields in a IPA packet status structure to store field values in local variables with names related to the field. - Pass a void pointer rather than an (equivalent) status pointer to two functions called by ipa_endpoint_status_parse(). - Use "rule" rather than "val" as the name of a variable that holds a routing rule ID. - Consistently use "IPA packet status" rather than "status element" when referring to this data structure. Signed-off-by: Alex Elder Signed-off-by: David S. Miller --- drivers/net/ipa/ipa_endpoint.c | 43 ++++++++++++++++++++-------------- 1 file changed, 25 insertions(+), 18 deletions(-) diff --git a/drivers/net/ipa/ipa_endpoint.c b/drivers/net/ipa/ipa_endpoint.c index ee3c29b1efea..5097eb1bbadb 100644 --- a/drivers/net/ipa/ipa_endpoint.c +++ b/drivers/net/ipa/ipa_endpoint.c @@ -1182,8 +1182,8 @@ static void ipa_endpoint_status(struct ipa_endpoint *endpoint) val |= ipa_reg_encode(reg, STATUS_ENDP, status_endpoint_id); } - /* STATUS_LOCATION is 0, meaning status element precedes - * packet (not present for IPA v4.5+) + /* STATUS_LOCATION is 0, meaning IPA packet status + * precedes the packet (not present for IPA v4.5+) */ /* STATUS_PKT_SUPPRESS_FMASK is 0 (not present for v4.0+) */ } @@ -1339,8 +1339,8 @@ static bool ipa_endpoint_skb_build(struct ipa_endpoint *endpoint, return skb != NULL; } -/* The format of a packet status element is the same for several status - * types (opcodes). Other types aren't currently supported. + /* The format of an IPA packet status structure is the same for several + * status types (opcodes). Other types aren't currently supported. */ static bool ipa_status_format_packet(enum ipa_status_opcode opcode) { @@ -1358,9 +1358,11 @@ static bool ipa_status_format_packet(enum ipa_status_opcode opcode) static bool ipa_endpoint_status_skip(struct ipa_endpoint *endpoint, const struct ipa_status *status) { + enum ipa_status_opcode opcode; u32 endpoint_id; - if (!ipa_status_format_packet(status->opcode)) + opcode = status->opcode; + if (!ipa_status_format_packet(opcode)) return true; endpoint_id = u8_get_bits(status->endp_dst_idx, @@ -1371,14 +1373,16 @@ static bool ipa_endpoint_status_skip(struct ipa_endpoint *endpoint, return false; /* Don't skip this packet, process it */ } -static bool ipa_endpoint_status_tag(struct ipa_endpoint *endpoint, - const struct ipa_status *status) +static bool ipa_endpoint_status_tag_valid(struct ipa_endpoint *endpoint, + const struct ipa_status *status) { struct ipa_endpoint *command_endpoint; + enum ipa_status_mask status_mask; struct ipa *ipa = endpoint->ipa; u32 endpoint_id; - if (!le16_get_bits(status->mask, IPA_STATUS_MASK_TAG_VALID)) + status_mask = le16_get_bits(status->mask, IPA_STATUS_MASK_TAG_VALID); + if (!status_mask) return false; /* No valid tag */ /* The status contains a valid tag. We know the packet was sent to @@ -1404,20 +1408,23 @@ static bool ipa_endpoint_status_tag(struct ipa_endpoint *endpoint, static bool ipa_endpoint_status_drop(struct ipa_endpoint *endpoint, const struct ipa_status *status) { - u32 val; + enum ipa_status_exception exception; + u32 rule; /* If the status indicates a tagged transfer, we'll drop the packet */ - if (ipa_endpoint_status_tag(endpoint, status)) + if (ipa_endpoint_status_tag_valid(endpoint, status)) return true; /* Deaggregation exceptions we drop; all other types we consume */ - if (status->exception) - return status->exception == IPA_STATUS_EXCEPTION_DEAGGR; + exception = status->exception; + if (exception) + return exception == IPA_STATUS_EXCEPTION_DEAGGR; /* Drop the packet if it fails to match a routing rule; otherwise no */ - val = le32_get_bits(status->flags1, IPA_STATUS_FLAGS1_RT_RULE_ID_FMASK); + rule = le32_get_bits(status->flags1, + IPA_STATUS_FLAGS1_RT_RULE_ID_FMASK); - return val == field_max(IPA_STATUS_FLAGS1_RT_RULE_ID_FMASK); + return rule == field_max(IPA_STATUS_FLAGS1_RT_RULE_ID_FMASK); } static void ipa_endpoint_status_parse(struct ipa_endpoint *endpoint, @@ -1443,15 +1450,15 @@ static void ipa_endpoint_status_parse(struct ipa_endpoint *endpoint, /* Skip over status packets that lack packet data */ length = le16_to_cpu(status->pkt_len); - if (!length || ipa_endpoint_status_skip(endpoint, status)) { + if (!length || ipa_endpoint_status_skip(endpoint, data)) { data += IPA_STATUS_SIZE; resid -= IPA_STATUS_SIZE; continue; } /* Compute the amount of buffer space consumed by the packet, - * including the status element. If the hardware is configured - * to pad packet data to an aligned boundary, account for that. + * including the status. If the hardware is configured to + * pad packet data to an aligned boundary, account for that. * And if checksum offload is enabled a trailer containing * computed checksum information will be appended. */ @@ -1460,7 +1467,7 @@ static void ipa_endpoint_status_parse(struct ipa_endpoint *endpoint, if (endpoint->config.checksum) len += sizeof(struct rmnet_map_dl_csum_trailer); - if (!ipa_endpoint_status_drop(endpoint, status)) { + if (!ipa_endpoint_status_drop(endpoint, data)) { void *data2; u32 extra; From ebd2a82ecea8f6cb9165d6a05c23da16e1ec5669 Mon Sep 17 00:00:00 2001 From: Alex Elder Date: Wed, 25 Jan 2023 14:45:44 -0600 Subject: [PATCH 7/8] net: ipa: introduce generalized status decoder Stop assuming the IPA packet status has a fixed format (defined by a C structure). Instead, use a function to extract each field from a block of data interpreted as an IPA packet status. Define an enumerated type that identifies the fields that can be extracted. The current function extracts fields based on the existing ipa_status structure format (which is no longer used). Define IPA_STATUS_RULE_MISS, to replace the calls to field_max() to represent that condition; those depended on the knowing the width of a filter or router rule in the IPA packet status structure. Signed-off-by: Alex Elder Signed-off-by: David S. Miller --- drivers/net/ipa/ipa_endpoint.c | 158 +++++++++++++++++++++++++-------- 1 file changed, 120 insertions(+), 38 deletions(-) diff --git a/drivers/net/ipa/ipa_endpoint.c b/drivers/net/ipa/ipa_endpoint.c index 5097eb1bbadb..3f6c3e2b6ec9 100644 --- a/drivers/net/ipa/ipa_endpoint.c +++ b/drivers/net/ipa/ipa_endpoint.c @@ -81,32 +81,118 @@ enum ipa_status_mask { IPA_STATUS_MASK_BYTE_LIMIT = BIT(15), }; +/* Special IPA filter/router rule field value indicating "rule miss" */ +#define IPA_STATUS_RULE_MISS 0x3ff /* 10-bit filter/router rule fields */ + /** The IPA status nat_type field uses enum ipa_nat_type hardware values */ -/* Status element provided by hardware */ -struct ipa_status { - u8 opcode; /* enum ipa_status_opcode */ - u8 exception; /* enum ipa_status_exception */ - __le16 mask; /* enum ipa_status_bit (bitmask) */ - __le16 pkt_len; - u8 endp_src_idx; - u8 endp_dst_idx; - __le32 metadata; - __le32 flags1; - __le64 flags2; - __le32 flags3; - __le32 flags4; +/* enum ipa_status_field_id - IPA packet status structure field identifiers */ +enum ipa_status_field_id { + STATUS_OPCODE, /* enum ipa_status_opcode */ + STATUS_EXCEPTION, /* enum ipa_status_exception */ + STATUS_MASK, /* enum ipa_status_mask (bitmask) */ + STATUS_LENGTH, + STATUS_SRC_ENDPOINT, + STATUS_DST_ENDPOINT, + STATUS_METADATA, + STATUS_FILTER_LOCAL, /* Boolean */ + STATUS_FILTER_HASH, /* Boolean */ + STATUS_FILTER_GLOBAL, /* Boolean */ + STATUS_FILTER_RETAIN, /* Boolean */ + STATUS_FILTER_RULE_INDEX, + STATUS_ROUTER_LOCAL, /* Boolean */ + STATUS_ROUTER_HASH, /* Boolean */ + STATUS_UCP, /* Boolean */ + STATUS_ROUTER_TABLE, + STATUS_ROUTER_RULE_INDEX, + STATUS_NAT_HIT, /* Boolean */ + STATUS_NAT_INDEX, + STATUS_NAT_TYPE, /* enum ipa_nat_type */ + STATUS_TAG_LOW32, /* Low-order 32 bits of 48-bit tag */ + STATUS_TAG_HIGH16, /* High-order 16 bits of 48-bit tag */ + STATUS_SEQUENCE, + STATUS_TIME_OF_DAY, + STATUS_HEADER_LOCAL, /* Boolean */ + STATUS_HEADER_OFFSET, + STATUS_FRAG_HIT, /* Boolean */ + STATUS_FRAG_RULE_INDEX, }; -/* Field masks for struct ipa_status structure fields */ -#define IPA_STATUS_SRC_IDX_FMASK GENMASK(4, 0) -#define IPA_STATUS_DST_IDX_FMASK GENMASK(4, 0) -#define IPA_STATUS_FLAGS1_RT_RULE_ID_FMASK GENMASK(31, 22) -#define IPA_STATUS_FLAGS2_TAG_FMASK GENMASK_ULL(63, 16) - /* Size in bytes of an IPA packet status structure */ #define IPA_STATUS_SIZE sizeof(__le32[4]) +/* IPA status structure decoder; looks up field values for a structure */ +static u32 ipa_status_extract(const void *data, enum ipa_status_field_id field) +{ + const __le32 *word = data; + + switch (field) { + case STATUS_OPCODE: + return le32_get_bits(word[0], GENMASK(7, 0)); + case STATUS_EXCEPTION: + return le32_get_bits(word[0], GENMASK(15, 8)); + case STATUS_MASK: + return le32_get_bits(word[0], GENMASK(31, 16)); + case STATUS_LENGTH: + return le32_get_bits(word[1], GENMASK(15, 0)); + case STATUS_SRC_ENDPOINT: + return le32_get_bits(word[1], GENMASK(20, 16)); + /* Status word 1, bits 21-23 are reserved */ + case STATUS_DST_ENDPOINT: + return le32_get_bits(word[1], GENMASK(28, 24)); + /* Status word 1, bits 29-31 are reserved */ + case STATUS_METADATA: + return le32_to_cpu(word[2]); + case STATUS_FILTER_LOCAL: + return le32_get_bits(word[3], GENMASK(0, 0)); + case STATUS_FILTER_HASH: + return le32_get_bits(word[3], GENMASK(1, 1)); + case STATUS_FILTER_GLOBAL: + return le32_get_bits(word[3], GENMASK(2, 2)); + case STATUS_FILTER_RETAIN: + return le32_get_bits(word[3], GENMASK(3, 3)); + case STATUS_FILTER_RULE_INDEX: + return le32_get_bits(word[3], GENMASK(13, 4)); + case STATUS_ROUTER_LOCAL: + return le32_get_bits(word[3], GENMASK(14, 14)); + case STATUS_ROUTER_HASH: + return le32_get_bits(word[3], GENMASK(15, 15)); + case STATUS_UCP: + return le32_get_bits(word[3], GENMASK(16, 16)); + case STATUS_ROUTER_TABLE: + return le32_get_bits(word[3], GENMASK(21, 17)); + case STATUS_ROUTER_RULE_INDEX: + return le32_get_bits(word[3], GENMASK(31, 22)); + case STATUS_NAT_HIT: + return le32_get_bits(word[4], GENMASK(0, 0)); + case STATUS_NAT_INDEX: + return le32_get_bits(word[4], GENMASK(13, 1)); + case STATUS_NAT_TYPE: + return le32_get_bits(word[4], GENMASK(15, 14)); + case STATUS_TAG_LOW32: + return le32_get_bits(word[4], GENMASK(31, 16)) | + (le32_get_bits(word[5], GENMASK(15, 0)) << 16); + case STATUS_TAG_HIGH16: + return le32_get_bits(word[5], GENMASK(31, 16)); + case STATUS_SEQUENCE: + return le32_get_bits(word[6], GENMASK(7, 0)); + case STATUS_TIME_OF_DAY: + return le32_get_bits(word[6], GENMASK(31, 8)); + case STATUS_HEADER_LOCAL: + return le32_get_bits(word[7], GENMASK(0, 0)); + case STATUS_HEADER_OFFSET: + return le32_get_bits(word[7], GENMASK(10, 1)); + case STATUS_FRAG_HIT: + return le32_get_bits(word[7], GENMASK(11, 11)); + case STATUS_FRAG_RULE_INDEX: + return le32_get_bits(word[7], GENMASK(15, 12)); + /* Status word 7, bits 16-31 are reserved */ + default: + WARN(true, "%s: bad field_id %u\n", __func__, field); + return 0; + } +} + /* Compute the aggregation size value to use for a given buffer size */ static u32 ipa_aggr_size_kb(u32 rx_buffer_size, bool aggr_hard_limit) { @@ -1355,33 +1441,32 @@ static bool ipa_status_format_packet(enum ipa_status_opcode opcode) } } -static bool ipa_endpoint_status_skip(struct ipa_endpoint *endpoint, - const struct ipa_status *status) +static bool +ipa_endpoint_status_skip(struct ipa_endpoint *endpoint, const void *data) { enum ipa_status_opcode opcode; u32 endpoint_id; - opcode = status->opcode; + opcode = ipa_status_extract(data, STATUS_OPCODE); if (!ipa_status_format_packet(opcode)) return true; - endpoint_id = u8_get_bits(status->endp_dst_idx, - IPA_STATUS_DST_IDX_FMASK); + endpoint_id = ipa_status_extract(data, STATUS_DST_ENDPOINT); if (endpoint_id != endpoint->endpoint_id) return true; return false; /* Don't skip this packet, process it */ } -static bool ipa_endpoint_status_tag_valid(struct ipa_endpoint *endpoint, - const struct ipa_status *status) +static bool +ipa_endpoint_status_tag_valid(struct ipa_endpoint *endpoint, const void *data) { struct ipa_endpoint *command_endpoint; enum ipa_status_mask status_mask; struct ipa *ipa = endpoint->ipa; u32 endpoint_id; - status_mask = le16_get_bits(status->mask, IPA_STATUS_MASK_TAG_VALID); + status_mask = ipa_status_extract(data, STATUS_MASK); if (!status_mask) return false; /* No valid tag */ @@ -1390,8 +1475,7 @@ static bool ipa_endpoint_status_tag_valid(struct ipa_endpoint *endpoint, * If the packet came from the AP->command TX endpoint we know * this packet was sent as part of the pipeline clear process. */ - endpoint_id = u8_get_bits(status->endp_src_idx, - IPA_STATUS_SRC_IDX_FMASK); + endpoint_id = ipa_status_extract(data, STATUS_SRC_ENDPOINT); command_endpoint = ipa->name_map[IPA_ENDPOINT_AP_COMMAND_TX]; if (endpoint_id == command_endpoint->endpoint_id) { complete(&ipa->completion); @@ -1405,26 +1489,25 @@ static bool ipa_endpoint_status_tag_valid(struct ipa_endpoint *endpoint, } /* Return whether the status indicates the packet should be dropped */ -static bool ipa_endpoint_status_drop(struct ipa_endpoint *endpoint, - const struct ipa_status *status) +static bool +ipa_endpoint_status_drop(struct ipa_endpoint *endpoint, const void *data) { enum ipa_status_exception exception; u32 rule; /* If the status indicates a tagged transfer, we'll drop the packet */ - if (ipa_endpoint_status_tag_valid(endpoint, status)) + if (ipa_endpoint_status_tag_valid(endpoint, data)) return true; /* Deaggregation exceptions we drop; all other types we consume */ - exception = status->exception; + exception = ipa_status_extract(data, STATUS_EXCEPTION); if (exception) return exception == IPA_STATUS_EXCEPTION_DEAGGR; /* Drop the packet if it fails to match a routing rule; otherwise no */ - rule = le32_get_bits(status->flags1, - IPA_STATUS_FLAGS1_RT_RULE_ID_FMASK); + rule = ipa_status_extract(data, STATUS_ROUTER_RULE_INDEX); - return rule == field_max(IPA_STATUS_FLAGS1_RT_RULE_ID_FMASK); + return rule == IPA_STATUS_RULE_MISS; } static void ipa_endpoint_status_parse(struct ipa_endpoint *endpoint, @@ -1436,7 +1519,6 @@ static void ipa_endpoint_status_parse(struct ipa_endpoint *endpoint, u32 resid = total_len; while (resid) { - const struct ipa_status *status = data; u32 length; u32 align; u32 len; @@ -1449,7 +1531,7 @@ static void ipa_endpoint_status_parse(struct ipa_endpoint *endpoint, } /* Skip over status packets that lack packet data */ - length = le16_to_cpu(status->pkt_len); + length = ipa_status_extract(data, STATUS_LENGTH); if (!length || ipa_endpoint_status_skip(endpoint, data)) { data += IPA_STATUS_SIZE; resid -= IPA_STATUS_SIZE; From 55c6eae70ff1833a5080bfef0bed10ebf4e22cec Mon Sep 17 00:00:00 2001 From: Alex Elder Date: Wed, 25 Jan 2023 14:45:45 -0600 Subject: [PATCH 8/8] net: ipa: add IPA v5.0 packet status support Update ipa_status_extract() to support IPA v5.0 and beyond. Because the format of the IPA packet status depends on the version, pass an IPA pointer to the function. Signed-off-by: Alex Elder Signed-off-by: David S. Miller --- drivers/net/ipa/ipa_endpoint.c | 52 +++++++++++++++++++++++----------- 1 file changed, 36 insertions(+), 16 deletions(-) diff --git a/drivers/net/ipa/ipa_endpoint.c b/drivers/net/ipa/ipa_endpoint.c index 3f6c3e2b6ec9..ce7f2d6e447e 100644 --- a/drivers/net/ipa/ipa_endpoint.c +++ b/drivers/net/ipa/ipa_endpoint.c @@ -122,8 +122,10 @@ enum ipa_status_field_id { #define IPA_STATUS_SIZE sizeof(__le32[4]) /* IPA status structure decoder; looks up field values for a structure */ -static u32 ipa_status_extract(const void *data, enum ipa_status_field_id field) +static u32 ipa_status_extract(struct ipa *ipa, const void *data, + enum ipa_status_field_id field) { + enum ipa_version version = ipa->version; const __le32 *word = data; switch (field) { @@ -136,10 +138,15 @@ static u32 ipa_status_extract(const void *data, enum ipa_status_field_id field) case STATUS_LENGTH: return le32_get_bits(word[1], GENMASK(15, 0)); case STATUS_SRC_ENDPOINT: - return le32_get_bits(word[1], GENMASK(20, 16)); - /* Status word 1, bits 21-23 are reserved */ + if (version < IPA_VERSION_5_0) + return le32_get_bits(word[1], GENMASK(20, 16)); + return le32_get_bits(word[1], GENMASK(23, 16)); + /* Status word 1, bits 21-23 are reserved (not IPA v5.0+) */ + /* Status word 1, bits 24-26 are reserved (IPA v5.0+) */ case STATUS_DST_ENDPOINT: - return le32_get_bits(word[1], GENMASK(28, 24)); + if (version < IPA_VERSION_5_0) + return le32_get_bits(word[1], GENMASK(28, 24)); + return le32_get_bits(word[7], GENMASK(23, 16)); /* Status word 1, bits 29-31 are reserved */ case STATUS_METADATA: return le32_to_cpu(word[2]); @@ -153,14 +160,23 @@ static u32 ipa_status_extract(const void *data, enum ipa_status_field_id field) return le32_get_bits(word[3], GENMASK(3, 3)); case STATUS_FILTER_RULE_INDEX: return le32_get_bits(word[3], GENMASK(13, 4)); + /* ROUTER_TABLE is in word 3, bits 14-21 (IPA v5.0+) */ case STATUS_ROUTER_LOCAL: - return le32_get_bits(word[3], GENMASK(14, 14)); + if (version < IPA_VERSION_5_0) + return le32_get_bits(word[3], GENMASK(14, 14)); + return le32_get_bits(word[1], GENMASK(27, 27)); case STATUS_ROUTER_HASH: - return le32_get_bits(word[3], GENMASK(15, 15)); + if (version < IPA_VERSION_5_0) + return le32_get_bits(word[3], GENMASK(15, 15)); + return le32_get_bits(word[1], GENMASK(28, 28)); case STATUS_UCP: - return le32_get_bits(word[3], GENMASK(16, 16)); + if (version < IPA_VERSION_5_0) + return le32_get_bits(word[3], GENMASK(16, 16)); + return le32_get_bits(word[7], GENMASK(31, 31)); case STATUS_ROUTER_TABLE: - return le32_get_bits(word[3], GENMASK(21, 17)); + if (version < IPA_VERSION_5_0) + return le32_get_bits(word[3], GENMASK(21, 17)); + return le32_get_bits(word[3], GENMASK(21, 14)); case STATUS_ROUTER_RULE_INDEX: return le32_get_bits(word[3], GENMASK(31, 22)); case STATUS_NAT_HIT: @@ -186,7 +202,8 @@ static u32 ipa_status_extract(const void *data, enum ipa_status_field_id field) return le32_get_bits(word[7], GENMASK(11, 11)); case STATUS_FRAG_RULE_INDEX: return le32_get_bits(word[7], GENMASK(15, 12)); - /* Status word 7, bits 16-31 are reserved */ + /* Status word 7, bits 16-30 are reserved */ + /* Status word 7, bit 31 is reserved (not IPA v5.0+) */ default: WARN(true, "%s: bad field_id %u\n", __func__, field); return 0; @@ -1444,14 +1461,15 @@ static bool ipa_status_format_packet(enum ipa_status_opcode opcode) static bool ipa_endpoint_status_skip(struct ipa_endpoint *endpoint, const void *data) { + struct ipa *ipa = endpoint->ipa; enum ipa_status_opcode opcode; u32 endpoint_id; - opcode = ipa_status_extract(data, STATUS_OPCODE); + opcode = ipa_status_extract(ipa, data, STATUS_OPCODE); if (!ipa_status_format_packet(opcode)) return true; - endpoint_id = ipa_status_extract(data, STATUS_DST_ENDPOINT); + endpoint_id = ipa_status_extract(ipa, data, STATUS_DST_ENDPOINT); if (endpoint_id != endpoint->endpoint_id) return true; @@ -1466,7 +1484,7 @@ ipa_endpoint_status_tag_valid(struct ipa_endpoint *endpoint, const void *data) struct ipa *ipa = endpoint->ipa; u32 endpoint_id; - status_mask = ipa_status_extract(data, STATUS_MASK); + status_mask = ipa_status_extract(ipa, data, STATUS_MASK); if (!status_mask) return false; /* No valid tag */ @@ -1475,7 +1493,7 @@ ipa_endpoint_status_tag_valid(struct ipa_endpoint *endpoint, const void *data) * If the packet came from the AP->command TX endpoint we know * this packet was sent as part of the pipeline clear process. */ - endpoint_id = ipa_status_extract(data, STATUS_SRC_ENDPOINT); + endpoint_id = ipa_status_extract(ipa, data, STATUS_SRC_ENDPOINT); command_endpoint = ipa->name_map[IPA_ENDPOINT_AP_COMMAND_TX]; if (endpoint_id == command_endpoint->endpoint_id) { complete(&ipa->completion); @@ -1493,6 +1511,7 @@ static bool ipa_endpoint_status_drop(struct ipa_endpoint *endpoint, const void *data) { enum ipa_status_exception exception; + struct ipa *ipa = endpoint->ipa; u32 rule; /* If the status indicates a tagged transfer, we'll drop the packet */ @@ -1500,12 +1519,12 @@ ipa_endpoint_status_drop(struct ipa_endpoint *endpoint, const void *data) return true; /* Deaggregation exceptions we drop; all other types we consume */ - exception = ipa_status_extract(data, STATUS_EXCEPTION); + exception = ipa_status_extract(ipa, data, STATUS_EXCEPTION); if (exception) return exception == IPA_STATUS_EXCEPTION_DEAGGR; /* Drop the packet if it fails to match a routing rule; otherwise no */ - rule = ipa_status_extract(data, STATUS_ROUTER_RULE_INDEX); + rule = ipa_status_extract(ipa, data, STATUS_ROUTER_RULE_INDEX); return rule == IPA_STATUS_RULE_MISS; } @@ -1516,6 +1535,7 @@ static void ipa_endpoint_status_parse(struct ipa_endpoint *endpoint, u32 buffer_size = endpoint->config.rx.buffer_size; void *data = page_address(page) + NET_SKB_PAD; u32 unused = buffer_size - total_len; + struct ipa *ipa = endpoint->ipa; u32 resid = total_len; while (resid) { @@ -1531,7 +1551,7 @@ static void ipa_endpoint_status_parse(struct ipa_endpoint *endpoint, } /* Skip over status packets that lack packet data */ - length = ipa_status_extract(data, STATUS_LENGTH); + length = ipa_status_extract(ipa, data, STATUS_LENGTH); if (!length || ipa_endpoint_status_skip(endpoint, data)) { data += IPA_STATUS_SIZE; resid -= IPA_STATUS_SIZE;