Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

Merge branch 'ipa-abstract-status'

Alex Elder says:

====================
net: ipa: abstract status parsing

Under some circumstances, IPA generates a "packet status" structure
that describes information about a packet. This is used, for
example, when offload hardware detects an error in a packet, or
otherwise discovers a packet needs special handling. In this case,
the status is delivered (along with the packet it describes) to a
"default" endpoint so that it can be handled by the AP.

Until now, the structure of this status information hasn't changed.
However, to support more than 32 endpoints, this structure required
some changes, such that some fields are rearranged in ways that are
tricky to represent using C code.

This series updates code related to the IPA status structure. The
first patch uses a local variable to avoid recomputing a packet
length more than once. The second stops using sizeof() to determine
the size of an IPA packet status structure. Patches 3-5 extend the
definitions for values held in packet status fields. Patch 6 does a
little general cleanup to make patch 7 simpler. Patch 7 stops using
a C structure to represent packet status; instead, a new function
fetches values "by name" from a buffer containing such a structure.
The last patch updates this function so it also supports IPA v5.0+.
====================

Signed-off-by: David S. Miller <davem@davemloft.net>

+217 -73
+212 -68
drivers/net/ipa/ipa_endpoint.c
··· 34 34 35 35 #define IPA_ENDPOINT_RESET_AGGR_RETRY_MAX 3 36 36 37 - /** enum ipa_status_opcode - status element opcode hardware values */ 38 - enum ipa_status_opcode { 39 - IPA_STATUS_OPCODE_PACKET = 0x01, 40 - IPA_STATUS_OPCODE_DROPPED_PACKET = 0x04, 41 - IPA_STATUS_OPCODE_SUSPENDED_PACKET = 0x08, 42 - IPA_STATUS_OPCODE_PACKET_2ND_PASS = 0x40, 37 + /** enum ipa_status_opcode - IPA status opcode field hardware values */ 38 + enum ipa_status_opcode { /* *Not* a bitmask */ 39 + IPA_STATUS_OPCODE_PACKET = 1, 40 + IPA_STATUS_OPCODE_NEW_RULE_PACKET = 2, 41 + IPA_STATUS_OPCODE_DROPPED_PACKET = 4, 42 + IPA_STATUS_OPCODE_SUSPENDED_PACKET = 8, 43 + IPA_STATUS_OPCODE_LOG = 16, 44 + IPA_STATUS_OPCODE_DCMP = 32, 45 + IPA_STATUS_OPCODE_PACKET_2ND_PASS = 64, 43 46 }; 44 47 45 - /** enum ipa_status_exception - status element exception type */ 46 - enum ipa_status_exception { 48 + /** enum ipa_status_exception - IPA status exception field hardware values */ 49 + enum ipa_status_exception { /* *Not* a bitmask */ 47 50 /* 0 means no exception */ 48 - IPA_STATUS_EXCEPTION_DEAGGR = 0x01, 51 + IPA_STATUS_EXCEPTION_DEAGGR = 1, 52 + IPA_STATUS_EXCEPTION_IPTYPE = 4, 53 + IPA_STATUS_EXCEPTION_PACKET_LENGTH = 8, 54 + IPA_STATUS_EXCEPTION_FRAG_RULE_MISS = 16, 55 + IPA_STATUS_EXCEPTION_SW_FILTER = 32, 56 + IPA_STATUS_EXCEPTION_NAT = 64, /* IPv4 */ 57 + IPA_STATUS_EXCEPTION_IPV6_CONN_TRACK = 64, /* IPv6 */ 58 + IPA_STATUS_EXCEPTION_UC = 128, 59 + IPA_STATUS_EXCEPTION_INVALID_ENDPOINT = 129, 60 + IPA_STATUS_EXCEPTION_HEADER_INSERT = 136, 61 + IPA_STATUS_EXCEPTION_CHEKCSUM = 229, 49 62 }; 50 63 51 - /* Status element provided by hardware */ 52 - struct ipa_status { 53 - u8 opcode; /* enum ipa_status_opcode */ 54 - u8 exception; /* enum ipa_status_exception */ 55 - __le16 mask; 56 - __le16 pkt_len; 57 - u8 endp_src_idx; 58 - u8 endp_dst_idx; 59 - __le32 metadata; 60 - __le32 flags1; 61 - __le64 flags2; 62 - __le32 flags3; 63 - __le32 flags4; 64 + /** enum ipa_status_mask - IPA status mask field bitmask hardware values */ 65 + enum ipa_status_mask { 66 + IPA_STATUS_MASK_FRAG_PROCESS = BIT(0), 67 + IPA_STATUS_MASK_FILT_PROCESS = BIT(1), 68 + IPA_STATUS_MASK_NAT_PROCESS = BIT(2), 69 + IPA_STATUS_MASK_ROUTE_PROCESS = BIT(3), 70 + IPA_STATUS_MASK_TAG_VALID = BIT(4), 71 + IPA_STATUS_MASK_FRAGMENT = BIT(5), 72 + IPA_STATUS_MASK_FIRST_FRAGMENT = BIT(6), 73 + IPA_STATUS_MASK_V4 = BIT(7), 74 + IPA_STATUS_MASK_CKSUM_PROCESS = BIT(8), 75 + IPA_STATUS_MASK_AGGR_PROCESS = BIT(9), 76 + IPA_STATUS_MASK_DEST_EOT = BIT(10), 77 + IPA_STATUS_MASK_DEAGGR_PROCESS = BIT(11), 78 + IPA_STATUS_MASK_DEAGG_FIRST = BIT(12), 79 + IPA_STATUS_MASK_SRC_EOT = BIT(13), 80 + IPA_STATUS_MASK_PREV_EOT = BIT(14), 81 + IPA_STATUS_MASK_BYTE_LIMIT = BIT(15), 64 82 }; 65 83 66 - /* Field masks for struct ipa_status structure fields */ 67 - #define IPA_STATUS_MASK_TAG_VALID_FMASK GENMASK(4, 4) 68 - #define IPA_STATUS_SRC_IDX_FMASK GENMASK(4, 0) 69 - #define IPA_STATUS_DST_IDX_FMASK GENMASK(4, 0) 70 - #define IPA_STATUS_FLAGS1_RT_RULE_ID_FMASK GENMASK(31, 22) 71 - #define IPA_STATUS_FLAGS2_TAG_FMASK GENMASK_ULL(63, 16) 84 + /* Special IPA filter/router rule field value indicating "rule miss" */ 85 + #define IPA_STATUS_RULE_MISS 0x3ff /* 10-bit filter/router rule fields */ 86 + 87 + /** The IPA status nat_type field uses enum ipa_nat_type hardware values */ 88 + 89 + /* enum ipa_status_field_id - IPA packet status structure field identifiers */ 90 + enum ipa_status_field_id { 91 + STATUS_OPCODE, /* enum ipa_status_opcode */ 92 + STATUS_EXCEPTION, /* enum ipa_status_exception */ 93 + STATUS_MASK, /* enum ipa_status_mask (bitmask) */ 94 + STATUS_LENGTH, 95 + STATUS_SRC_ENDPOINT, 96 + STATUS_DST_ENDPOINT, 97 + STATUS_METADATA, 98 + STATUS_FILTER_LOCAL, /* Boolean */ 99 + STATUS_FILTER_HASH, /* Boolean */ 100 + STATUS_FILTER_GLOBAL, /* Boolean */ 101 + STATUS_FILTER_RETAIN, /* Boolean */ 102 + STATUS_FILTER_RULE_INDEX, 103 + STATUS_ROUTER_LOCAL, /* Boolean */ 104 + STATUS_ROUTER_HASH, /* Boolean */ 105 + STATUS_UCP, /* Boolean */ 106 + STATUS_ROUTER_TABLE, 107 + STATUS_ROUTER_RULE_INDEX, 108 + STATUS_NAT_HIT, /* Boolean */ 109 + STATUS_NAT_INDEX, 110 + STATUS_NAT_TYPE, /* enum ipa_nat_type */ 111 + STATUS_TAG_LOW32, /* Low-order 32 bits of 48-bit tag */ 112 + STATUS_TAG_HIGH16, /* High-order 16 bits of 48-bit tag */ 113 + STATUS_SEQUENCE, 114 + STATUS_TIME_OF_DAY, 115 + STATUS_HEADER_LOCAL, /* Boolean */ 116 + STATUS_HEADER_OFFSET, 117 + STATUS_FRAG_HIT, /* Boolean */ 118 + STATUS_FRAG_RULE_INDEX, 119 + }; 120 + 121 + /* Size in bytes of an IPA packet status structure */ 122 + #define IPA_STATUS_SIZE sizeof(__le32[4]) 123 + 124 + /* IPA status structure decoder; looks up field values for a structure */ 125 + static u32 ipa_status_extract(struct ipa *ipa, const void *data, 126 + enum ipa_status_field_id field) 127 + { 128 + enum ipa_version version = ipa->version; 129 + const __le32 *word = data; 130 + 131 + switch (field) { 132 + case STATUS_OPCODE: 133 + return le32_get_bits(word[0], GENMASK(7, 0)); 134 + case STATUS_EXCEPTION: 135 + return le32_get_bits(word[0], GENMASK(15, 8)); 136 + case STATUS_MASK: 137 + return le32_get_bits(word[0], GENMASK(31, 16)); 138 + case STATUS_LENGTH: 139 + return le32_get_bits(word[1], GENMASK(15, 0)); 140 + case STATUS_SRC_ENDPOINT: 141 + if (version < IPA_VERSION_5_0) 142 + return le32_get_bits(word[1], GENMASK(20, 16)); 143 + return le32_get_bits(word[1], GENMASK(23, 16)); 144 + /* Status word 1, bits 21-23 are reserved (not IPA v5.0+) */ 145 + /* Status word 1, bits 24-26 are reserved (IPA v5.0+) */ 146 + case STATUS_DST_ENDPOINT: 147 + if (version < IPA_VERSION_5_0) 148 + return le32_get_bits(word[1], GENMASK(28, 24)); 149 + return le32_get_bits(word[7], GENMASK(23, 16)); 150 + /* Status word 1, bits 29-31 are reserved */ 151 + case STATUS_METADATA: 152 + return le32_to_cpu(word[2]); 153 + case STATUS_FILTER_LOCAL: 154 + return le32_get_bits(word[3], GENMASK(0, 0)); 155 + case STATUS_FILTER_HASH: 156 + return le32_get_bits(word[3], GENMASK(1, 1)); 157 + case STATUS_FILTER_GLOBAL: 158 + return le32_get_bits(word[3], GENMASK(2, 2)); 159 + case STATUS_FILTER_RETAIN: 160 + return le32_get_bits(word[3], GENMASK(3, 3)); 161 + case STATUS_FILTER_RULE_INDEX: 162 + return le32_get_bits(word[3], GENMASK(13, 4)); 163 + /* ROUTER_TABLE is in word 3, bits 14-21 (IPA v5.0+) */ 164 + case STATUS_ROUTER_LOCAL: 165 + if (version < IPA_VERSION_5_0) 166 + return le32_get_bits(word[3], GENMASK(14, 14)); 167 + return le32_get_bits(word[1], GENMASK(27, 27)); 168 + case STATUS_ROUTER_HASH: 169 + if (version < IPA_VERSION_5_0) 170 + return le32_get_bits(word[3], GENMASK(15, 15)); 171 + return le32_get_bits(word[1], GENMASK(28, 28)); 172 + case STATUS_UCP: 173 + if (version < IPA_VERSION_5_0) 174 + return le32_get_bits(word[3], GENMASK(16, 16)); 175 + return le32_get_bits(word[7], GENMASK(31, 31)); 176 + case STATUS_ROUTER_TABLE: 177 + if (version < IPA_VERSION_5_0) 178 + return le32_get_bits(word[3], GENMASK(21, 17)); 179 + return le32_get_bits(word[3], GENMASK(21, 14)); 180 + case STATUS_ROUTER_RULE_INDEX: 181 + return le32_get_bits(word[3], GENMASK(31, 22)); 182 + case STATUS_NAT_HIT: 183 + return le32_get_bits(word[4], GENMASK(0, 0)); 184 + case STATUS_NAT_INDEX: 185 + return le32_get_bits(word[4], GENMASK(13, 1)); 186 + case STATUS_NAT_TYPE: 187 + return le32_get_bits(word[4], GENMASK(15, 14)); 188 + case STATUS_TAG_LOW32: 189 + return le32_get_bits(word[4], GENMASK(31, 16)) | 190 + (le32_get_bits(word[5], GENMASK(15, 0)) << 16); 191 + case STATUS_TAG_HIGH16: 192 + return le32_get_bits(word[5], GENMASK(31, 16)); 193 + case STATUS_SEQUENCE: 194 + return le32_get_bits(word[6], GENMASK(7, 0)); 195 + case STATUS_TIME_OF_DAY: 196 + return le32_get_bits(word[6], GENMASK(31, 8)); 197 + case STATUS_HEADER_LOCAL: 198 + return le32_get_bits(word[7], GENMASK(0, 0)); 199 + case STATUS_HEADER_OFFSET: 200 + return le32_get_bits(word[7], GENMASK(10, 1)); 201 + case STATUS_FRAG_HIT: 202 + return le32_get_bits(word[7], GENMASK(11, 11)); 203 + case STATUS_FRAG_RULE_INDEX: 204 + return le32_get_bits(word[7], GENMASK(15, 12)); 205 + /* Status word 7, bits 16-30 are reserved */ 206 + /* Status word 7, bit 31 is reserved (not IPA v5.0+) */ 207 + default: 208 + WARN(true, "%s: bad field_id %u\n", __func__, field); 209 + return 0; 210 + } 211 + } 72 212 73 213 /* Compute the aggregation size value to use for a given buffer size */ 74 214 static u32 ipa_aggr_size_kb(u32 rx_buffer_size, bool aggr_hard_limit) ··· 688 548 return; 689 549 690 550 reg = ipa_reg(ipa, ENDP_INIT_NAT); 691 - val = ipa_reg_encode(reg, NAT_EN, IPA_NAT_BYPASS); 551 + val = ipa_reg_encode(reg, NAT_EN, IPA_NAT_TYPE_BYPASS); 692 552 693 553 iowrite32(val, ipa->reg_virt + ipa_reg_n_offset(reg, endpoint_id)); 694 554 } ··· 1285 1145 val |= ipa_reg_encode(reg, STATUS_ENDP, 1286 1146 status_endpoint_id); 1287 1147 } 1288 - /* STATUS_LOCATION is 0, meaning status element precedes 1289 - * packet (not present for IPA v4.5+) 1148 + /* STATUS_LOCATION is 0, meaning IPA packet status 1149 + * precedes the packet (not present for IPA v4.5+) 1290 1150 */ 1291 1151 /* STATUS_PKT_SUPPRESS_FMASK is 0 (not present for v4.0+) */ 1292 1152 } ··· 1442 1302 return skb != NULL; 1443 1303 } 1444 1304 1445 - /* The format of a packet status element is the same for several status 1446 - * types (opcodes). Other types aren't currently supported. 1305 + /* The format of an IPA packet status structure is the same for several 1306 + * status types (opcodes). Other types aren't currently supported. 1447 1307 */ 1448 1308 static bool ipa_status_format_packet(enum ipa_status_opcode opcode) 1449 1309 { ··· 1458 1318 } 1459 1319 } 1460 1320 1461 - static bool ipa_endpoint_status_skip(struct ipa_endpoint *endpoint, 1462 - const struct ipa_status *status) 1321 + static bool 1322 + ipa_endpoint_status_skip(struct ipa_endpoint *endpoint, const void *data) 1463 1323 { 1324 + struct ipa *ipa = endpoint->ipa; 1325 + enum ipa_status_opcode opcode; 1464 1326 u32 endpoint_id; 1465 1327 1466 - if (!ipa_status_format_packet(status->opcode)) 1328 + opcode = ipa_status_extract(ipa, data, STATUS_OPCODE); 1329 + if (!ipa_status_format_packet(opcode)) 1467 1330 return true; 1468 - if (!status->pkt_len) 1469 - return true; 1470 - endpoint_id = u8_get_bits(status->endp_dst_idx, 1471 - IPA_STATUS_DST_IDX_FMASK); 1331 + 1332 + endpoint_id = ipa_status_extract(ipa, data, STATUS_DST_ENDPOINT); 1472 1333 if (endpoint_id != endpoint->endpoint_id) 1473 1334 return true; 1474 1335 1475 1336 return false; /* Don't skip this packet, process it */ 1476 1337 } 1477 1338 1478 - static bool ipa_endpoint_status_tag(struct ipa_endpoint *endpoint, 1479 - const struct ipa_status *status) 1339 + static bool 1340 + ipa_endpoint_status_tag_valid(struct ipa_endpoint *endpoint, const void *data) 1480 1341 { 1481 1342 struct ipa_endpoint *command_endpoint; 1343 + enum ipa_status_mask status_mask; 1482 1344 struct ipa *ipa = endpoint->ipa; 1483 1345 u32 endpoint_id; 1484 1346 1485 - if (!le16_get_bits(status->mask, IPA_STATUS_MASK_TAG_VALID_FMASK)) 1347 + status_mask = ipa_status_extract(ipa, data, STATUS_MASK); 1348 + if (!status_mask) 1486 1349 return false; /* No valid tag */ 1487 1350 1488 1351 /* The status contains a valid tag. We know the packet was sent to ··· 1493 1350 * If the packet came from the AP->command TX endpoint we know 1494 1351 * this packet was sent as part of the pipeline clear process. 1495 1352 */ 1496 - endpoint_id = u8_get_bits(status->endp_src_idx, 1497 - IPA_STATUS_SRC_IDX_FMASK); 1353 + endpoint_id = ipa_status_extract(ipa, data, STATUS_SRC_ENDPOINT); 1498 1354 command_endpoint = ipa->name_map[IPA_ENDPOINT_AP_COMMAND_TX]; 1499 1355 if (endpoint_id == command_endpoint->endpoint_id) { 1500 1356 complete(&ipa->completion); ··· 1507 1365 } 1508 1366 1509 1367 /* Return whether the status indicates the packet should be dropped */ 1510 - static bool ipa_endpoint_status_drop(struct ipa_endpoint *endpoint, 1511 - const struct ipa_status *status) 1368 + static bool 1369 + ipa_endpoint_status_drop(struct ipa_endpoint *endpoint, const void *data) 1512 1370 { 1513 - u32 val; 1371 + enum ipa_status_exception exception; 1372 + struct ipa *ipa = endpoint->ipa; 1373 + u32 rule; 1514 1374 1515 1375 /* If the status indicates a tagged transfer, we'll drop the packet */ 1516 - if (ipa_endpoint_status_tag(endpoint, status)) 1376 + if (ipa_endpoint_status_tag_valid(endpoint, data)) 1517 1377 return true; 1518 1378 1519 1379 /* Deaggregation exceptions we drop; all other types we consume */ 1520 - if (status->exception) 1521 - return status->exception == IPA_STATUS_EXCEPTION_DEAGGR; 1380 + exception = ipa_status_extract(ipa, data, STATUS_EXCEPTION); 1381 + if (exception) 1382 + return exception == IPA_STATUS_EXCEPTION_DEAGGR; 1522 1383 1523 1384 /* Drop the packet if it fails to match a routing rule; otherwise no */ 1524 - val = le32_get_bits(status->flags1, IPA_STATUS_FLAGS1_RT_RULE_ID_FMASK); 1385 + rule = ipa_status_extract(ipa, data, STATUS_ROUTER_RULE_INDEX); 1525 1386 1526 - return val == field_max(IPA_STATUS_FLAGS1_RT_RULE_ID_FMASK); 1387 + return rule == IPA_STATUS_RULE_MISS; 1527 1388 } 1528 1389 1529 1390 static void ipa_endpoint_status_parse(struct ipa_endpoint *endpoint, ··· 1535 1390 u32 buffer_size = endpoint->config.rx.buffer_size; 1536 1391 void *data = page_address(page) + NET_SKB_PAD; 1537 1392 u32 unused = buffer_size - total_len; 1393 + struct ipa *ipa = endpoint->ipa; 1538 1394 u32 resid = total_len; 1539 1395 1540 1396 while (resid) { 1541 - const struct ipa_status *status = data; 1397 + u32 length; 1542 1398 u32 align; 1543 1399 u32 len; 1544 1400 1545 - if (resid < sizeof(*status)) { 1401 + if (resid < IPA_STATUS_SIZE) { 1546 1402 dev_err(&endpoint->ipa->pdev->dev, 1547 1403 "short message (%u bytes < %zu byte status)\n", 1548 - resid, sizeof(*status)); 1404 + resid, IPA_STATUS_SIZE); 1549 1405 break; 1550 1406 } 1551 1407 1552 1408 /* Skip over status packets that lack packet data */ 1553 - if (ipa_endpoint_status_skip(endpoint, status)) { 1554 - data += sizeof(*status); 1555 - resid -= sizeof(*status); 1409 + length = ipa_status_extract(ipa, data, STATUS_LENGTH); 1410 + if (!length || ipa_endpoint_status_skip(endpoint, data)) { 1411 + data += IPA_STATUS_SIZE; 1412 + resid -= IPA_STATUS_SIZE; 1556 1413 continue; 1557 1414 } 1558 1415 1559 1416 /* Compute the amount of buffer space consumed by the packet, 1560 - * including the status element. If the hardware is configured 1561 - * to pad packet data to an aligned boundary, account for that. 1417 + * including the status. If the hardware is configured to 1418 + * pad packet data to an aligned boundary, account for that. 1562 1419 * And if checksum offload is enabled a trailer containing 1563 1420 * computed checksum information will be appended. 1564 1421 */ 1565 1422 align = endpoint->config.rx.pad_align ? : 1; 1566 - len = le16_to_cpu(status->pkt_len); 1567 - len = sizeof(*status) + ALIGN(len, align); 1423 + len = IPA_STATUS_SIZE + ALIGN(length, align); 1568 1424 if (endpoint->config.checksum) 1569 1425 len += sizeof(struct rmnet_map_dl_csum_trailer); 1570 1426 1571 - if (!ipa_endpoint_status_drop(endpoint, status)) { 1427 + if (!ipa_endpoint_status_drop(endpoint, data)) { 1572 1428 void *data2; 1573 1429 u32 extra; 1574 - u32 len2; 1575 1430 1576 1431 /* Client receives only packet data (no status) */ 1577 - data2 = data + sizeof(*status); 1578 - len2 = le16_to_cpu(status->pkt_len); 1432 + data2 = data + IPA_STATUS_SIZE; 1579 1433 1580 1434 /* Have the true size reflect the extra unused space in 1581 1435 * the original receive buffer. Distribute the "cost" ··· 1582 1438 * buffer. 1583 1439 */ 1584 1440 extra = DIV_ROUND_CLOSEST(unused * len, total_len); 1585 - ipa_endpoint_skb_copy(endpoint, data2, len2, extra); 1441 + ipa_endpoint_skb_copy(endpoint, data2, length, extra); 1586 1442 } 1587 1443 1588 1444 /* Consume status and the full packet it describes */
+5 -5
drivers/net/ipa/ipa_reg.h
··· 382 382 NAT_EN, 383 383 }; 384 384 385 - /** enum ipa_nat_en - ENDP_INIT_NAT register NAT_EN field value */ 386 - enum ipa_nat_en { 387 - IPA_NAT_BYPASS = 0x0, 388 - IPA_NAT_SRC = 0x1, 389 - IPA_NAT_DST = 0x2, 385 + /** enum ipa_nat_type - ENDP_INIT_NAT register NAT_EN field value */ 386 + enum ipa_nat_type { 387 + IPA_NAT_TYPE_BYPASS = 0, 388 + IPA_NAT_TYPE_SRC = 1, 389 + IPA_NAT_TYPE_DST = 2, 390 390 }; 391 391 392 392 /* ENDP_INIT_HDR register */