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

Merge branch 'net-ipa-validation-cleanup'

Alex Elder says:

====================
net: ipa: validation cleanup

This series gathers a set of IPA driver cleanups, mostly involving
code that ensures certain things are known to be correct *early*
(either at build or initializatin time), so they can be assumed good
during normal operation.

The first removes three constant symbols, by making a (reasonable)
assumption that a routing table consists of entries for the modem
followed by entries for the AP, with no unused entries between them.

The second removes two checks that are redundant (they verify the
sizes of two memory regions are in range, which will have been done
earlier for all regions).

The third adds some new checks to routing and filter tables that
can be done at "init time" (without requiring any access to IPA
hardware).

The fourth moves a check that routing and filter table addresses can
be encoded within certain IPA immediate commands, so it's performed
earlier; the checks can be done without touching IPA hardware. The
fifth moves some other command-related checks earlier, for the same
reason.

The sixth removes the definition ipa_table_valid(), because what it
does has become redundant. Finally, the last patch moves two more
validation calls so they're done very early in the probe process.
This will be required by some upcoming patches, which will record
the size of the routing and filter tables at this time so they're
available for subsequent initialization.
====================

Link: https://lore.kernel.org/r/20221021191340.4187935-1-elder@linaro.org
Signed-off-by: Paolo Abeni <pabeni@redhat.com>

+136 -120
+17 -36
drivers/net/ipa/ipa_cmd.c
··· 171 171 } 172 172 173 173 /* Validate a memory region holding a table */ 174 - bool ipa_cmd_table_valid(struct ipa *ipa, const struct ipa_mem *mem, bool route) 174 + bool ipa_cmd_table_init_valid(struct ipa *ipa, const struct ipa_mem *mem, 175 + bool route) 175 176 { 176 177 u32 offset_max = field_max(IP_FLTRT_FLAGS_NHASH_ADDR_FMASK); 177 178 u32 size_max = field_max(IP_FLTRT_FLAGS_NHASH_SIZE_FMASK); ··· 198 197 return false; 199 198 } 200 199 201 - /* Entire memory range must fit within IPA-local memory */ 202 - if (mem->offset > ipa->mem_size || 203 - mem->size > ipa->mem_size - mem->offset) { 204 - dev_err(dev, "%s table region out of range\n", table); 205 - dev_err(dev, " (0x%04x + 0x%04x > 0x%04x)\n", 206 - mem->offset, mem->size, ipa->mem_size); 207 - 208 - return false; 209 - } 210 - 211 200 return true; 212 201 } 213 202 214 203 /* Validate the memory region that holds headers */ 215 - static bool ipa_cmd_header_valid(struct ipa *ipa) 204 + static bool ipa_cmd_header_init_local_valid(struct ipa *ipa) 216 205 { 217 206 struct device *dev = &ipa->pdev->dev; 218 207 const struct ipa_mem *mem; ··· 244 253 if (size > size_max) { 245 254 dev_err(dev, "header table region size too large\n"); 246 255 dev_err(dev, " (0x%04x > 0x%08x)\n", size, size_max); 247 - 248 - return false; 249 - } 250 - 251 - /* Make sure the entire combined area fits in IPA memory */ 252 - if (size > ipa->mem_size || offset > ipa->mem_size - size) { 253 - dev_err(dev, "header table region out of range\n"); 254 - dev_err(dev, " (0x%04x + 0x%04x > 0x%04x)\n", 255 - offset, size, ipa->mem_size); 256 256 257 257 return false; 258 258 } ··· 318 336 return true; 319 337 } 320 338 321 - bool ipa_cmd_data_valid(struct ipa *ipa) 322 - { 323 - if (!ipa_cmd_header_valid(ipa)) 324 - return false; 325 - 326 - if (!ipa_cmd_register_write_valid(ipa)) 327 - return false; 328 - 329 - return true; 330 - } 331 - 332 - 333 339 int ipa_cmd_pool_init(struct gsi_channel *channel, u32 tre_max) 334 340 { 335 341 struct gsi_trans_info *trans_info = &channel->trans_info; 336 342 struct device *dev = channel->gsi->dev; 337 - 338 - /* This is as good a place as any to validate build constants */ 339 - ipa_cmd_validate_build(); 340 343 341 344 /* Command payloads are allocated one at a time, but a single 342 345 * transaction can require up to the maximum supported by the ··· 621 654 622 655 return gsi_channel_trans_alloc(&ipa->gsi, endpoint->channel_id, 623 656 tre_count, DMA_NONE); 657 + } 658 + 659 + /* Init function for immediate commands; there is no ipa_cmd_exit() */ 660 + int ipa_cmd_init(struct ipa *ipa) 661 + { 662 + ipa_cmd_validate_build(); 663 + 664 + if (!ipa_cmd_header_init_local_valid(ipa)) 665 + return -EINVAL; 666 + 667 + if (!ipa_cmd_register_write_valid(ipa)) 668 + return -EINVAL; 669 + 670 + return 0; 624 671 }
+13 -3
drivers/net/ipa/ipa_cmd.h
··· 47 47 }; 48 48 49 49 /** 50 - * ipa_cmd_table_valid() - Validate a memory region holding a table 50 + * ipa_cmd_table_init_valid() - Validate a memory region holding a table 51 51 * @ipa: - IPA pointer 52 52 * @mem: - IPA memory region descriptor 53 53 * @route: - Whether the region holds a route or filter table 54 54 * 55 55 * Return: true if region is valid, false otherwise 56 56 */ 57 - bool ipa_cmd_table_valid(struct ipa *ipa, const struct ipa_mem *mem, 58 - bool route); 57 + bool ipa_cmd_table_init_valid(struct ipa *ipa, const struct ipa_mem *mem, 58 + bool route); 59 59 60 60 /** 61 61 * ipa_cmd_data_valid() - Validate command-realted configuration is valid ··· 161 161 * available transactions are in use 162 162 */ 163 163 struct gsi_trans *ipa_cmd_trans_alloc(struct ipa *ipa, u32 tre_count); 164 + 165 + /** 166 + * ipa_cmd_init() - Initialize IPA immediate commands 167 + * @ipa: - IPA pointer 168 + * 169 + * Return: 0 if successful, or a negative error code 170 + * 171 + * There is no need for a matching ipa_cmd_exit() function. 172 + */ 173 + int ipa_cmd_init(struct ipa *ipa); 164 174 165 175 #endif /* _IPA_CMD_H_ */
+6 -8
drivers/net/ipa/ipa_mem.c
··· 366 366 while (--canary_count); 367 367 } 368 368 369 - /* Make sure filter and route table memory regions are valid */ 370 - if (!ipa_table_valid(ipa)) 371 - goto err_dma_free; 372 - 373 - /* Validate memory-related properties relevant to immediate commands */ 374 - if (!ipa_cmd_data_valid(ipa)) 375 - goto err_dma_free; 376 - 377 369 /* Verify the microcontroller ring alignment (if defined) */ 378 370 mem = ipa_mem_find(ipa, IPA_MEM_UC_EVENT_RING); 379 371 if (mem && mem->offset % 1024) { ··· 616 624 617 625 ipa->mem_count = mem_data->local_count; 618 626 ipa->mem = mem_data->local; 627 + 628 + /* Check the route and filter table memory regions */ 629 + if (!ipa_table_mem_valid(ipa, 0)) 630 + return -EINVAL; 631 + if (!ipa_table_mem_valid(ipa, IPA_ROUTE_MODEM_COUNT)) 632 + return -EINVAL; 619 633 620 634 ret = dma_set_mask_and_coherent(&ipa->pdev->dev, DMA_BIT_MASK(64)); 621 635 if (ret) {
+93 -65
drivers/net/ipa/ipa_table.c
··· 106 106 * ---------------------- 107 107 */ 108 108 109 - /* Assignment of route table entries to the modem and AP */ 110 - #define IPA_ROUTE_MODEM_MIN 0 111 - #define IPA_ROUTE_AP_MIN IPA_ROUTE_MODEM_COUNT 112 - #define IPA_ROUTE_AP_COUNT \ 113 - (IPA_ROUTE_COUNT_MAX - IPA_ROUTE_MODEM_COUNT) 114 - 115 109 /* Filter or route rules consist of a set of 32-bit values followed by a 116 110 * 32-bit all-zero rule list terminator. The "zero rule" is simply an 117 111 * all-zero rule followed by the list terminator. ··· 134 140 BUILD_BUG_ON(IPA_ROUTE_COUNT_MAX > 32); 135 141 /* The modem must be allotted at least one route table entry */ 136 142 BUILD_BUG_ON(!IPA_ROUTE_MODEM_COUNT); 137 - /* But it can't have more than what is available */ 138 - BUILD_BUG_ON(IPA_ROUTE_MODEM_COUNT > IPA_ROUTE_COUNT_MAX); 139 - 143 + /* AP must too, but we can't use more than what is available */ 144 + BUILD_BUG_ON(IPA_ROUTE_MODEM_COUNT >= IPA_ROUTE_COUNT_MAX); 140 145 } 141 146 142 - static bool 143 - ipa_table_valid_one(struct ipa *ipa, enum ipa_mem_id mem_id, bool route) 147 + static const struct ipa_mem * 148 + ipa_table_mem(struct ipa *ipa, bool filter, bool hashed, bool ipv6) 144 149 { 145 - const struct ipa_mem *mem = ipa_mem_find(ipa, mem_id); 146 - struct device *dev = &ipa->pdev->dev; 147 - u32 size; 150 + enum ipa_mem_id mem_id; 148 151 149 - if (route) 150 - size = IPA_ROUTE_COUNT_MAX * sizeof(__le64); 151 - else 152 - size = (1 + IPA_FILTER_COUNT_MAX) * sizeof(__le64); 152 + mem_id = filter ? hashed ? ipv6 ? IPA_MEM_V6_FILTER_HASHED 153 + : IPA_MEM_V4_FILTER_HASHED 154 + : ipv6 ? IPA_MEM_V6_FILTER 155 + : IPA_MEM_V4_FILTER 156 + : hashed ? ipv6 ? IPA_MEM_V6_ROUTE_HASHED 157 + : IPA_MEM_V4_ROUTE_HASHED 158 + : ipv6 ? IPA_MEM_V6_ROUTE 159 + : IPA_MEM_V4_ROUTE; 153 160 154 - if (!ipa_cmd_table_valid(ipa, mem, route)) 155 - return false; 156 - 157 - /* mem->size >= size is sufficient, but we'll demand more */ 158 - if (mem->size == size) 159 - return true; 160 - 161 - /* Hashed table regions can be zero size if hashing is not supported */ 162 - if (ipa_table_hash_support(ipa) && !mem->size) 163 - return true; 164 - 165 - dev_err(dev, "%s table region %u size 0x%02x, expected 0x%02x\n", 166 - route ? "route" : "filter", mem_id, mem->size, size); 167 - 168 - return false; 169 - } 170 - 171 - /* Verify the filter and route table memory regions are the expected size */ 172 - bool ipa_table_valid(struct ipa *ipa) 173 - { 174 - bool valid; 175 - 176 - valid = ipa_table_valid_one(ipa, IPA_MEM_V4_FILTER, false); 177 - valid = valid && ipa_table_valid_one(ipa, IPA_MEM_V6_FILTER, false); 178 - valid = valid && ipa_table_valid_one(ipa, IPA_MEM_V4_ROUTE, true); 179 - valid = valid && ipa_table_valid_one(ipa, IPA_MEM_V6_ROUTE, true); 180 - 181 - if (!ipa_table_hash_support(ipa)) 182 - return valid; 183 - 184 - valid = valid && ipa_table_valid_one(ipa, IPA_MEM_V4_FILTER_HASHED, 185 - false); 186 - valid = valid && ipa_table_valid_one(ipa, IPA_MEM_V6_FILTER_HASHED, 187 - false); 188 - valid = valid && ipa_table_valid_one(ipa, IPA_MEM_V4_ROUTE_HASHED, 189 - true); 190 - valid = valid && ipa_table_valid_one(ipa, IPA_MEM_V6_ROUTE_HASHED, 191 - true); 192 - 193 - return valid; 161 + return ipa_mem_find(ipa, mem_id); 194 162 } 195 163 196 164 bool ipa_filter_map_valid(struct ipa *ipa, u32 filter_map) ··· 298 342 } 299 343 300 344 if (modem) { 301 - first = IPA_ROUTE_MODEM_MIN; 345 + first = 0; 302 346 count = IPA_ROUTE_MODEM_COUNT; 303 347 } else { 304 - first = IPA_ROUTE_AP_MIN; 305 - count = IPA_ROUTE_AP_COUNT; 348 + first = IPA_ROUTE_MODEM_COUNT; 349 + count = IPA_ROUTE_COUNT_MAX - IPA_ROUTE_MODEM_COUNT; 306 350 } 307 351 308 352 ipa_table_reset_add(trans, false, first, count, IPA_MEM_V4_ROUTE); ··· 517 561 518 562 static bool ipa_route_id_modem(u32 route_id) 519 563 { 520 - return route_id >= IPA_ROUTE_MODEM_MIN && 521 - route_id <= IPA_ROUTE_MODEM_MIN + IPA_ROUTE_MODEM_COUNT - 1; 564 + return route_id < IPA_ROUTE_MODEM_COUNT; 522 565 } 523 566 524 567 /** ··· 566 611 ipa_route_config(ipa, true); 567 612 } 568 613 569 - /* 570 - * Initialize a coherent DMA allocation containing initialized filter and 614 + /* Zero modem_route_count means filter table memory check */ 615 + bool ipa_table_mem_valid(struct ipa *ipa, bool modem_route_count) 616 + { 617 + bool hash_support = ipa_table_hash_support(ipa); 618 + bool filter = !modem_route_count; 619 + const struct ipa_mem *mem_hashed; 620 + const struct ipa_mem *mem_ipv4; 621 + const struct ipa_mem *mem_ipv6; 622 + u32 count; 623 + 624 + /* IPv4 and IPv6 non-hashed tables are expected to be defined and 625 + * have the same size. Both must have at least two entries (and 626 + * would normally have more than that). 627 + */ 628 + mem_ipv4 = ipa_table_mem(ipa, filter, false, false); 629 + if (!mem_ipv4) 630 + return false; 631 + 632 + mem_ipv6 = ipa_table_mem(ipa, filter, false, true); 633 + if (!mem_ipv6) 634 + return false; 635 + 636 + if (mem_ipv4->size != mem_ipv6->size) 637 + return false; 638 + 639 + /* Table offset and size must fit in TABLE_INIT command fields */ 640 + if (!ipa_cmd_table_init_valid(ipa, mem_ipv4, !filter)) 641 + return false; 642 + 643 + /* Make sure the regions are big enough */ 644 + count = mem_ipv4->size / sizeof(__le64); 645 + if (count < 2) 646 + return false; 647 + if (filter) { 648 + /* Filter tables must able to hold the endpoint bitmap plus 649 + * an entry for each endpoint that supports filtering 650 + */ 651 + if (count < 1 + hweight32(ipa->filter_map)) 652 + return false; 653 + } else { 654 + /* Routing tables must be able to hold all modem entries, 655 + * plus at least one entry for the AP. 656 + */ 657 + if (count < modem_route_count + 1) 658 + return false; 659 + } 660 + 661 + /* If hashing is supported, hashed tables are expected to be defined, 662 + * and have the same size as non-hashed tables. If hashing is not 663 + * supported, hashed tables are expected to have zero size (or not 664 + * be defined). 665 + */ 666 + mem_hashed = ipa_table_mem(ipa, filter, true, false); 667 + if (hash_support) { 668 + if (!mem_hashed || mem_hashed->size != mem_ipv4->size) 669 + return false; 670 + } else { 671 + if (mem_hashed && mem_hashed->size) 672 + return false; 673 + } 674 + 675 + /* Same check for IPv6 tables */ 676 + mem_hashed = ipa_table_mem(ipa, filter, true, true); 677 + if (hash_support) { 678 + if (!mem_hashed || mem_hashed->size != mem_ipv6->size) 679 + return false; 680 + } else { 681 + if (mem_hashed && mem_hashed->size) 682 + return false; 683 + } 684 + 685 + return true; 686 + } 687 + 688 + /* Initialize a coherent DMA allocation containing initialized filter and 571 689 * route table data. This is used when initializing or resetting the IPA 572 690 * filter or route table. 573 691 *
+7 -8
drivers/net/ipa/ipa_table.h
··· 20 20 #define IPA_ROUTE_COUNT_MAX 15 21 21 22 22 /** 23 - * ipa_table_valid() - Validate route and filter table memory regions 24 - * @ipa: IPA pointer 25 - * 26 - * Return: true if all regions are valid, false otherwise 27 - */ 28 - bool ipa_table_valid(struct ipa *ipa); 29 - 30 - /** 31 23 * ipa_filter_map_valid() - Validate a filter table endpoint bitmap 32 24 * @ipa: IPA pointer 33 25 * @filter_mask: Filter table endpoint bitmap to check ··· 77 85 * @ipa: IPA pointer 78 86 */ 79 87 void ipa_table_exit(struct ipa *ipa); 88 + 89 + /** 90 + * ipa_table_mem_valid() - Validate sizes of table memory regions 91 + * @ipa: IPA pointer 92 + * @modem_route_count: Number of modem route table entries 93 + */ 94 + bool ipa_table_mem_valid(struct ipa *ipa, bool modem_route_count); 80 95 81 96 #endif /* _IPA_TABLE_H_ */