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

Configure Feed

Select the types of activity you want to include in your feed.

Merge branch 'net-mlx5-hws-refactor-action-ste-handling'

Tariq Toukan says:

====================
net/mlx5: HWS, Refactor action STE handling

This patch series by Vlad refactors how action STEs are handled for
hardware steering.

Definitions
----------

* STE (Steering Table Entry): a building block for steering rules.
Simple rules consist of a single STE that specifies both the match
value and what actions to do. For more complex rules we have one or
more match STEs that point to one or more action STEs. It is these
action STEs which this patch series is primarily concerned with.

* RTC (Rule Table Context): a table that contains STEs. A matcher
currently consists of a match RTC and, if necessary, an action RTC.
This patch series decouples action RTCs from matchers and moves action
RTCs to a central pool.

* Matcher: a logical container for steering rules. While the items above
describe hardware concepts, a matcher is purely a software construct.

Current situation
-----------------

As mentioned above, a matcher currently consists of a match RTC (or
more, in case of complex matchers) and zero or one action STCs. An
action STC is only allocated if the matcher contains sufficiently
complicated action templates, or many actions.

When adding a rule, we decide based on its action template whether it
requires action STEs. If yes, we allocate the required number of action
STEs from the matcher's action STE.

When updating a rule, we need to prevent the rule ever being in an
invalid state. So we need to allocate and write new action STEs first,
then update the match STE to point to them, and finally release the old
action STEs. So there is a state when a rule needs double the action
STEs it normally uses.

Thus, for a given matcher of log_sz=N, log_action_ste_sz=A, the action
STC log_size is (N + A + 1). We need enough space to hold all the rules'
action STEs, and effectively double that space to account for the not
very common case of rules being updated. We could manage with much fewer
extra action STEs, but RTCs are allocated in powers of two. This results
in effective utilization of action RTCs of 50%, outside rule update
cases.

This is further complicated when resizing matchers. To avoid updating
all the rules to point to new match STEs, we keep existing action RTCs
around as resize_data, and only free them when the matcher is freed.

Action STE pool
---------------

This patch series decouples action RTCs from matchers by creating a
per-queue pool. When a rule needs to allocate action STEs it does so
from the pool, creating a new RTC if needed. During update two sets of
action STEs are in use, possibly from different RTCs.

The pool is sharded per-queue to avoid lock contention. Each per-queue
pool consists of 3 elements, corresponding to rx-only, tx-only and
rx-and-tx use cases. The series takes this approach because rules that
are bidirectional require that their action STEs have the same index in
the rx- and tx-RTCs, and using a single RTC would result in
unidirectional rules wasting the STEs for the unused direction.

Pool elements, in turn, consist of a list of RTCs. The driver
progressively allocates larger RTCs as they are needed to amortize the
cost of allocation.

Allocation of elements (STEs) inside RTCs is modelled by an existing
mechanism, somewhat confusingly also known as a pool. The first few
patches in the series refactor this abstraction to simplify it and adapt
it to the new schema.

Finally, this series implements periodic cleanup of unused action RTCs
as a new feature. Previously, once a matcher allocated an action RTC, it
would only be freed when the matcher is freed. This resulted in a lot of
wasted memory for matchers that had previously grown, but were now
mostly unused.

Conversely, action STE pools have a timestamp of when they were last
used. A cleanup routine periodically checks all pools. If a pool's last
usage was too far in the past, it is destroyed.

Benchmarks
----------

The test module creates a batch of (1 << 18) rules per queue and then
deletes them, in a loop. The rules are complex enough to require two
action STEs per rule.

Each queue is manipulated from a separate kernel workqueue, so there is
a 1:1 correspondence between threads and queues.

There are sleep statements between insert and delete batches so that
memory usage can be evaluated using `free -m`. The numbers below are the
diff between base memory usage (without the mlx5 module inserted) and
peak usage while running a test. The values are rounded to the nearest
hundred megabytes. The `queues` column lists how many queues the test
used.

queues mem_before mem_after
1 1300M 800M
4 4000M 2300M
8 7300M 3300M

Across all of the tests, insertion and deletion rates are the same
before and after these patches.

Summary of the patches
----------------------

* Patch 1: Fix matcher action template attach to avoid overrunning the
buffer and correctly report errors.
* Patches 2-7: Cleanup the existing pool abstraction. Clarify semantics,
and use cases, simplify API and callers.
* Patch 8: Implement the new action STE pool structure.
* Patch 9: Use the action STE pool when manipulating rules.
* Patch 10: Remove action RTC from matcher.
* Patch 11: Add logic to periodically check and free unused action RTCs.
* Patch 12: Export action STE tables in debugfs for our dump tool.
====================

Link: https://patch.msgid.link/1744312662-356571-1-git-send-email-tariqt@nvidia.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>

+971 -968
+2 -1
drivers/net/ethernet/mellanox/mlx5/core/Makefile
··· 154 154 steering/hws/vport.o \ 155 155 steering/hws/bwc_complex.o \ 156 156 steering/hws/fs_hws_pools.o \ 157 - steering/hws/fs_hws.o 157 + steering/hws/fs_hws.o \ 158 + steering/hws/action_ste_pool.o 158 159 159 160 # 160 161 # SF device
+23 -33
drivers/net/ethernet/mellanox/mlx5/core/steering/hws/action.c
··· 238 238 enum mlx5hws_table_type table_type, 239 239 bool is_mirror) 240 240 { 241 + struct mlx5hws_pool *pool; 241 242 bool use_fixup = false; 242 243 u32 fw_tbl_type; 243 244 u32 base_id; ··· 254 253 use_fixup = true; 255 254 break; 256 255 } 256 + pool = stc_attr->ste_table.ste_pool; 257 257 if (!is_mirror) 258 - base_id = mlx5hws_pool_chunk_get_base_id(stc_attr->ste_table.ste_pool, 259 - &stc_attr->ste_table.ste); 258 + base_id = mlx5hws_pool_get_base_id(pool); 260 259 else 261 - base_id = 262 - mlx5hws_pool_chunk_get_base_mirror_id(stc_attr->ste_table.ste_pool, 263 - &stc_attr->ste_table.ste); 260 + base_id = mlx5hws_pool_get_base_mirror_id(pool); 264 261 265 262 *fixup_stc_attr = *stc_attr; 266 263 fixup_stc_attr->ste_table.ste_obj_id = base_id; ··· 336 337 if (!mlx5hws_context_cap_dynamic_reparse(ctx)) 337 338 stc_attr->reparse_mode = MLX5_IFC_STC_REPARSE_IGNORE; 338 339 339 - obj_0_id = mlx5hws_pool_chunk_get_base_id(stc_pool, stc); 340 + obj_0_id = mlx5hws_pool_get_base_id(stc_pool); 340 341 341 342 /* According to table/action limitation change the stc_attr */ 342 343 use_fixup = hws_action_fixup_stc_attr(ctx, stc_attr, &fixup_stc_attr, table_type, false); ··· 352 353 if (table_type == MLX5HWS_TABLE_TYPE_FDB) { 353 354 u32 obj_1_id; 354 355 355 - obj_1_id = mlx5hws_pool_chunk_get_base_mirror_id(stc_pool, stc); 356 + obj_1_id = mlx5hws_pool_get_base_mirror_id(stc_pool); 356 357 357 358 use_fixup = hws_action_fixup_stc_attr(ctx, stc_attr, 358 359 &fixup_stc_attr, ··· 392 393 stc_attr.action_type = MLX5_IFC_STC_ACTION_TYPE_DROP; 393 394 stc_attr.action_offset = MLX5HWS_ACTION_OFFSET_HIT; 394 395 stc_attr.stc_offset = stc->offset; 395 - obj_id = mlx5hws_pool_chunk_get_base_id(stc_pool, stc); 396 + obj_id = mlx5hws_pool_get_base_id(stc_pool); 396 397 mlx5hws_cmd_stc_modify(ctx->mdev, obj_id, &stc_attr); 397 398 398 399 if (table_type == MLX5HWS_TABLE_TYPE_FDB) { 399 - obj_id = mlx5hws_pool_chunk_get_base_mirror_id(stc_pool, stc); 400 + obj_id = mlx5hws_pool_get_base_mirror_id(stc_pool); 400 401 mlx5hws_cmd_stc_modify(ctx->mdev, obj_id, &stc_attr); 401 402 } 402 403 ··· 1574 1575 return definer; 1575 1576 } 1576 1577 1577 - static struct mlx5hws_matcher_action_ste * 1578 + static struct mlx5hws_range_action_table * 1578 1579 hws_action_create_dest_match_range_table(struct mlx5hws_context *ctx, 1579 1580 struct mlx5hws_definer *definer, 1580 1581 u32 miss_ft_id) 1581 1582 { 1582 1583 struct mlx5hws_cmd_rtc_create_attr rtc_attr = {0}; 1583 - struct mlx5hws_action_default_stc *default_stc; 1584 - struct mlx5hws_matcher_action_ste *table_ste; 1584 + struct mlx5hws_range_action_table *table_ste; 1585 1585 struct mlx5hws_pool_attr pool_attr = {0}; 1586 1586 struct mlx5hws_pool *ste_pool, *stc_pool; 1587 - struct mlx5hws_pool_chunk *ste; 1588 1587 u32 *rtc_0_id, *rtc_1_id; 1589 1588 u32 obj_id; 1590 1589 int ret; ··· 1601 1604 1602 1605 pool_attr.table_type = MLX5HWS_TABLE_TYPE_FDB; 1603 1606 pool_attr.pool_type = MLX5HWS_POOL_TYPE_STE; 1604 - pool_attr.flags = MLX5HWS_POOL_FLAGS_FOR_STE_ACTION_POOL; 1605 1607 pool_attr.alloc_log_sz = 1; 1606 1608 table_ste->pool = mlx5hws_pool_create(ctx, &pool_attr); 1607 1609 if (!table_ste->pool) { ··· 1612 1616 rtc_0_id = &table_ste->rtc_0_id; 1613 1617 rtc_1_id = &table_ste->rtc_1_id; 1614 1618 ste_pool = table_ste->pool; 1615 - ste = &table_ste->ste; 1616 - ste->order = 1; 1617 1619 1618 1620 rtc_attr.log_size = 0; 1619 1621 rtc_attr.log_depth = 0; ··· 1623 1629 rtc_attr.fw_gen_wqe = true; 1624 1630 rtc_attr.is_scnd_range = true; 1625 1631 1626 - obj_id = mlx5hws_pool_chunk_get_base_id(ste_pool, ste); 1632 + obj_id = mlx5hws_pool_get_base_id(ste_pool); 1627 1633 1628 1634 rtc_attr.pd = ctx->pd_num; 1629 1635 rtc_attr.ste_base = obj_id; 1630 - rtc_attr.ste_offset = ste->offset; 1631 1636 rtc_attr.reparse_mode = mlx5hws_context_get_reparse_mode(ctx); 1632 1637 rtc_attr.table_type = mlx5hws_table_get_res_fw_ft_type(MLX5HWS_TABLE_TYPE_FDB, false); 1633 1638 1634 1639 /* STC is a single resource (obj_id), use any STC for the ID */ 1635 1640 stc_pool = ctx->stc_pool; 1636 - default_stc = ctx->common_res.default_stc; 1637 - obj_id = mlx5hws_pool_chunk_get_base_id(stc_pool, &default_stc->default_hit); 1641 + obj_id = mlx5hws_pool_get_base_id(stc_pool); 1638 1642 rtc_attr.stc_base = obj_id; 1639 1643 1640 1644 ret = mlx5hws_cmd_rtc_create(ctx->mdev, &rtc_attr, rtc_0_id); ··· 1642 1650 } 1643 1651 1644 1652 /* Create mirror RTC */ 1645 - obj_id = mlx5hws_pool_chunk_get_base_mirror_id(ste_pool, ste); 1653 + obj_id = mlx5hws_pool_get_base_mirror_id(ste_pool); 1646 1654 rtc_attr.ste_base = obj_id; 1647 1655 rtc_attr.table_type = mlx5hws_table_get_res_fw_ft_type(MLX5HWS_TABLE_TYPE_FDB, true); 1648 1656 1649 - obj_id = mlx5hws_pool_chunk_get_base_mirror_id(stc_pool, &default_stc->default_hit); 1657 + obj_id = mlx5hws_pool_get_base_mirror_id(stc_pool); 1650 1658 rtc_attr.stc_base = obj_id; 1651 1659 1652 1660 ret = mlx5hws_cmd_rtc_create(ctx->mdev, &rtc_attr, rtc_1_id); ··· 1669 1677 return NULL; 1670 1678 } 1671 1679 1672 - static void 1673 - hws_action_destroy_dest_match_range_table(struct mlx5hws_context *ctx, 1674 - struct mlx5hws_matcher_action_ste *table_ste) 1680 + static void hws_action_destroy_dest_match_range_table( 1681 + struct mlx5hws_context *ctx, 1682 + struct mlx5hws_range_action_table *table_ste) 1675 1683 { 1676 1684 mutex_lock(&ctx->ctrl_lock); 1677 1685 ··· 1683 1691 mutex_unlock(&ctx->ctrl_lock); 1684 1692 } 1685 1693 1686 - static int 1687 - hws_action_create_dest_match_range_fill_table(struct mlx5hws_context *ctx, 1688 - struct mlx5hws_matcher_action_ste *table_ste, 1689 - struct mlx5hws_action *hit_ft_action, 1690 - struct mlx5hws_definer *range_definer, 1691 - u32 min, u32 max) 1694 + static int hws_action_create_dest_match_range_fill_table( 1695 + struct mlx5hws_context *ctx, 1696 + struct mlx5hws_range_action_table *table_ste, 1697 + struct mlx5hws_action *hit_ft_action, 1698 + struct mlx5hws_definer *range_definer, u32 min, u32 max) 1692 1699 { 1693 1700 struct mlx5hws_wqe_gta_data_seg_ste match_wqe_data = {0}; 1694 1701 struct mlx5hws_wqe_gta_data_seg_ste range_wqe_data = {0}; ··· 1783 1792 u32 min, u32 max, u32 flags) 1784 1793 { 1785 1794 struct mlx5hws_cmd_stc_modify_attr stc_attr = {0}; 1786 - struct mlx5hws_matcher_action_ste *table_ste; 1795 + struct mlx5hws_range_action_table *table_ste; 1787 1796 struct mlx5hws_action *hit_ft_action; 1788 1797 struct mlx5hws_definer *definer; 1789 1798 struct mlx5hws_action *action; ··· 1828 1837 stc_attr.action_offset = MLX5HWS_ACTION_OFFSET_HIT; 1829 1838 stc_attr.action_type = MLX5_IFC_STC_ACTION_TYPE_JUMP_TO_STE_TABLE; 1830 1839 stc_attr.reparse_mode = MLX5_IFC_STC_REPARSE_IGNORE; 1831 - stc_attr.ste_table.ste = table_ste->ste; 1832 1840 stc_attr.ste_table.ste_pool = table_ste->pool; 1833 1841 stc_attr.ste_table.match_definer_id = ctx->caps->trivial_match_definer; 1834 1842
+7 -1
drivers/net/ethernet/mellanox/mlx5/core/steering/hws/action.h
··· 118 118 u8 only_term; 119 119 }; 120 120 121 + struct mlx5hws_range_action_table { 122 + struct mlx5hws_pool *pool; 123 + u32 rtc_0_id; 124 + u32 rtc_1_id; 125 + }; 126 + 121 127 struct mlx5hws_action { 122 128 u8 type; 123 129 u8 flags; ··· 192 186 size_t size; 193 187 } remove_header; 194 188 struct { 195 - struct mlx5hws_matcher_action_ste *table_ste; 189 + struct mlx5hws_range_action_table *table_ste; 196 190 struct mlx5hws_action *hit_ft_action; 197 191 struct mlx5hws_definer *definer; 198 192 } range;
+467
drivers/net/ethernet/mellanox/mlx5/core/steering/hws/action_ste_pool.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB 2 + /* Copyright (c) 2025 NVIDIA Corporation & Affiliates */ 3 + 4 + #include "internal.h" 5 + 6 + static const char * 7 + hws_pool_opt_to_str(enum mlx5hws_pool_optimize opt) 8 + { 9 + switch (opt) { 10 + case MLX5HWS_POOL_OPTIMIZE_NONE: 11 + return "rx-and-tx"; 12 + case MLX5HWS_POOL_OPTIMIZE_ORIG: 13 + return "rx-only"; 14 + case MLX5HWS_POOL_OPTIMIZE_MIRROR: 15 + return "tx-only"; 16 + default: 17 + return "unknown"; 18 + } 19 + } 20 + 21 + static int 22 + hws_action_ste_table_create_pool(struct mlx5hws_context *ctx, 23 + struct mlx5hws_action_ste_table *action_tbl, 24 + enum mlx5hws_pool_optimize opt, size_t log_sz) 25 + { 26 + struct mlx5hws_pool_attr pool_attr = { 0 }; 27 + 28 + pool_attr.pool_type = MLX5HWS_POOL_TYPE_STE; 29 + pool_attr.table_type = MLX5HWS_TABLE_TYPE_FDB; 30 + pool_attr.flags = MLX5HWS_POOL_FLAG_BUDDY; 31 + pool_attr.opt_type = opt; 32 + pool_attr.alloc_log_sz = log_sz; 33 + 34 + action_tbl->pool = mlx5hws_pool_create(ctx, &pool_attr); 35 + if (!action_tbl->pool) { 36 + mlx5hws_err(ctx, "Failed to allocate STE pool\n"); 37 + return -EINVAL; 38 + } 39 + 40 + return 0; 41 + } 42 + 43 + static int hws_action_ste_table_create_single_rtc( 44 + struct mlx5hws_context *ctx, 45 + struct mlx5hws_action_ste_table *action_tbl, 46 + enum mlx5hws_pool_optimize opt, size_t log_sz, bool tx) 47 + { 48 + struct mlx5hws_cmd_rtc_create_attr rtc_attr = { 0 }; 49 + u32 *rtc_id; 50 + 51 + rtc_attr.log_depth = 0; 52 + rtc_attr.update_index_mode = MLX5_IFC_RTC_STE_UPDATE_MODE_BY_OFFSET; 53 + /* Action STEs use the default always hit definer. */ 54 + rtc_attr.match_definer_0 = ctx->caps->trivial_match_definer; 55 + rtc_attr.is_frst_jumbo = false; 56 + rtc_attr.miss_ft_id = 0; 57 + rtc_attr.pd = ctx->pd_num; 58 + rtc_attr.reparse_mode = mlx5hws_context_get_reparse_mode(ctx); 59 + 60 + if (tx) { 61 + rtc_attr.table_type = FS_FT_FDB_TX; 62 + rtc_attr.ste_base = 63 + mlx5hws_pool_get_base_mirror_id(action_tbl->pool); 64 + rtc_attr.stc_base = 65 + mlx5hws_pool_get_base_mirror_id(ctx->stc_pool); 66 + rtc_attr.log_size = 67 + opt == MLX5HWS_POOL_OPTIMIZE_ORIG ? 0 : log_sz; 68 + rtc_id = &action_tbl->rtc_1_id; 69 + } else { 70 + rtc_attr.table_type = FS_FT_FDB_RX; 71 + rtc_attr.ste_base = mlx5hws_pool_get_base_id(action_tbl->pool); 72 + rtc_attr.stc_base = mlx5hws_pool_get_base_id(ctx->stc_pool); 73 + rtc_attr.log_size = 74 + opt == MLX5HWS_POOL_OPTIMIZE_MIRROR ? 0 : log_sz; 75 + rtc_id = &action_tbl->rtc_0_id; 76 + } 77 + 78 + return mlx5hws_cmd_rtc_create(ctx->mdev, &rtc_attr, rtc_id); 79 + } 80 + 81 + static int 82 + hws_action_ste_table_create_rtcs(struct mlx5hws_context *ctx, 83 + struct mlx5hws_action_ste_table *action_tbl, 84 + enum mlx5hws_pool_optimize opt, size_t log_sz) 85 + { 86 + int err; 87 + 88 + err = hws_action_ste_table_create_single_rtc(ctx, action_tbl, opt, 89 + log_sz, false); 90 + if (err) 91 + return err; 92 + 93 + err = hws_action_ste_table_create_single_rtc(ctx, action_tbl, opt, 94 + log_sz, true); 95 + if (err) { 96 + mlx5hws_cmd_rtc_destroy(ctx->mdev, action_tbl->rtc_0_id); 97 + return err; 98 + } 99 + 100 + return 0; 101 + } 102 + 103 + static void 104 + hws_action_ste_table_destroy_rtcs(struct mlx5hws_action_ste_table *action_tbl) 105 + { 106 + mlx5hws_cmd_rtc_destroy(action_tbl->pool->ctx->mdev, 107 + action_tbl->rtc_1_id); 108 + mlx5hws_cmd_rtc_destroy(action_tbl->pool->ctx->mdev, 109 + action_tbl->rtc_0_id); 110 + } 111 + 112 + static int 113 + hws_action_ste_table_create_stc(struct mlx5hws_context *ctx, 114 + struct mlx5hws_action_ste_table *action_tbl) 115 + { 116 + struct mlx5hws_cmd_stc_modify_attr stc_attr = { 0 }; 117 + 118 + stc_attr.action_offset = MLX5HWS_ACTION_OFFSET_HIT; 119 + stc_attr.action_type = MLX5_IFC_STC_ACTION_TYPE_JUMP_TO_STE_TABLE; 120 + stc_attr.reparse_mode = MLX5_IFC_STC_REPARSE_IGNORE; 121 + stc_attr.ste_table.ste_pool = action_tbl->pool; 122 + stc_attr.ste_table.match_definer_id = ctx->caps->trivial_match_definer; 123 + 124 + return mlx5hws_action_alloc_single_stc(ctx, &stc_attr, 125 + MLX5HWS_TABLE_TYPE_FDB, 126 + &action_tbl->stc); 127 + } 128 + 129 + static struct mlx5hws_action_ste_table * 130 + hws_action_ste_table_alloc(struct mlx5hws_action_ste_pool_element *parent_elem) 131 + { 132 + enum mlx5hws_pool_optimize opt = parent_elem->opt; 133 + struct mlx5hws_context *ctx = parent_elem->ctx; 134 + struct mlx5hws_action_ste_table *action_tbl; 135 + size_t log_sz; 136 + int err; 137 + 138 + log_sz = min(parent_elem->log_sz ? 139 + parent_elem->log_sz + 140 + MLX5HWS_ACTION_STE_TABLE_STEP_LOG_SZ : 141 + MLX5HWS_ACTION_STE_TABLE_INIT_LOG_SZ, 142 + MLX5HWS_ACTION_STE_TABLE_MAX_LOG_SZ); 143 + 144 + action_tbl = kzalloc(sizeof(*action_tbl), GFP_KERNEL); 145 + if (!action_tbl) 146 + return ERR_PTR(-ENOMEM); 147 + 148 + err = hws_action_ste_table_create_pool(ctx, action_tbl, opt, log_sz); 149 + if (err) 150 + goto free_tbl; 151 + 152 + err = hws_action_ste_table_create_rtcs(ctx, action_tbl, opt, log_sz); 153 + if (err) 154 + goto destroy_pool; 155 + 156 + err = hws_action_ste_table_create_stc(ctx, action_tbl); 157 + if (err) 158 + goto destroy_rtcs; 159 + 160 + action_tbl->parent_elem = parent_elem; 161 + INIT_LIST_HEAD(&action_tbl->list_node); 162 + action_tbl->last_used = jiffies; 163 + list_add(&action_tbl->list_node, &parent_elem->available); 164 + parent_elem->log_sz = log_sz; 165 + 166 + mlx5hws_dbg(ctx, 167 + "Allocated %s action STE table log_sz %zu; STEs (%d, %d); RTCs (%d, %d); STC %d\n", 168 + hws_pool_opt_to_str(opt), log_sz, 169 + mlx5hws_pool_get_base_id(action_tbl->pool), 170 + mlx5hws_pool_get_base_mirror_id(action_tbl->pool), 171 + action_tbl->rtc_0_id, action_tbl->rtc_1_id, 172 + action_tbl->stc.offset); 173 + 174 + return action_tbl; 175 + 176 + destroy_rtcs: 177 + hws_action_ste_table_destroy_rtcs(action_tbl); 178 + destroy_pool: 179 + mlx5hws_pool_destroy(action_tbl->pool); 180 + free_tbl: 181 + kfree(action_tbl); 182 + 183 + return ERR_PTR(err); 184 + } 185 + 186 + static void 187 + hws_action_ste_table_destroy(struct mlx5hws_action_ste_table *action_tbl) 188 + { 189 + struct mlx5hws_context *ctx = action_tbl->parent_elem->ctx; 190 + 191 + mlx5hws_dbg(ctx, 192 + "Destroying %s action STE table: STEs (%d, %d); RTCs (%d, %d); STC %d\n", 193 + hws_pool_opt_to_str(action_tbl->parent_elem->opt), 194 + mlx5hws_pool_get_base_id(action_tbl->pool), 195 + mlx5hws_pool_get_base_mirror_id(action_tbl->pool), 196 + action_tbl->rtc_0_id, action_tbl->rtc_1_id, 197 + action_tbl->stc.offset); 198 + 199 + mlx5hws_action_free_single_stc(ctx, MLX5HWS_TABLE_TYPE_FDB, 200 + &action_tbl->stc); 201 + hws_action_ste_table_destroy_rtcs(action_tbl); 202 + mlx5hws_pool_destroy(action_tbl->pool); 203 + 204 + list_del(&action_tbl->list_node); 205 + kfree(action_tbl); 206 + } 207 + 208 + static int 209 + hws_action_ste_pool_element_init(struct mlx5hws_context *ctx, 210 + struct mlx5hws_action_ste_pool_element *elem, 211 + enum mlx5hws_pool_optimize opt) 212 + { 213 + elem->ctx = ctx; 214 + elem->opt = opt; 215 + INIT_LIST_HEAD(&elem->available); 216 + INIT_LIST_HEAD(&elem->full); 217 + 218 + return 0; 219 + } 220 + 221 + static void hws_action_ste_pool_element_destroy( 222 + struct mlx5hws_action_ste_pool_element *elem) 223 + { 224 + struct mlx5hws_action_ste_table *action_tbl, *p; 225 + 226 + /* This should be empty, but attempt to free its elements anyway. */ 227 + list_for_each_entry_safe(action_tbl, p, &elem->full, list_node) 228 + hws_action_ste_table_destroy(action_tbl); 229 + 230 + list_for_each_entry_safe(action_tbl, p, &elem->available, list_node) 231 + hws_action_ste_table_destroy(action_tbl); 232 + } 233 + 234 + static int hws_action_ste_pool_init(struct mlx5hws_context *ctx, 235 + struct mlx5hws_action_ste_pool *pool) 236 + { 237 + enum mlx5hws_pool_optimize opt; 238 + int err; 239 + 240 + mutex_init(&pool->lock); 241 + 242 + /* Rules which are added for both RX and TX must use the same action STE 243 + * indices for both. If we were to use a single table, then RX-only and 244 + * TX-only rules would waste the unused entries. Thus, we use separate 245 + * table sets for the three cases. 246 + */ 247 + for (opt = MLX5HWS_POOL_OPTIMIZE_NONE; opt < MLX5HWS_POOL_OPTIMIZE_MAX; 248 + opt++) { 249 + err = hws_action_ste_pool_element_init(ctx, &pool->elems[opt], 250 + opt); 251 + if (err) 252 + goto destroy_elems; 253 + pool->elems[opt].parent_pool = pool; 254 + } 255 + 256 + return 0; 257 + 258 + destroy_elems: 259 + while (opt-- > MLX5HWS_POOL_OPTIMIZE_NONE) 260 + hws_action_ste_pool_element_destroy(&pool->elems[opt]); 261 + 262 + return err; 263 + } 264 + 265 + static void hws_action_ste_pool_destroy(struct mlx5hws_action_ste_pool *pool) 266 + { 267 + int opt; 268 + 269 + for (opt = MLX5HWS_POOL_OPTIMIZE_MAX - 1; 270 + opt >= MLX5HWS_POOL_OPTIMIZE_NONE; opt--) 271 + hws_action_ste_pool_element_destroy(&pool->elems[opt]); 272 + } 273 + 274 + static void hws_action_ste_pool_element_collect_stale( 275 + struct mlx5hws_action_ste_pool_element *elem, struct list_head *cleanup) 276 + { 277 + struct mlx5hws_action_ste_table *action_tbl, *p; 278 + unsigned long expire_time, now; 279 + 280 + expire_time = secs_to_jiffies(MLX5HWS_ACTION_STE_POOL_EXPIRE_SECONDS); 281 + now = jiffies; 282 + 283 + list_for_each_entry_safe(action_tbl, p, &elem->available, list_node) { 284 + if (mlx5hws_pool_full(action_tbl->pool) && 285 + time_before(action_tbl->last_used + expire_time, now)) 286 + list_move(&action_tbl->list_node, cleanup); 287 + } 288 + } 289 + 290 + static void hws_action_ste_table_cleanup_list(struct list_head *cleanup) 291 + { 292 + struct mlx5hws_action_ste_table *action_tbl, *p; 293 + 294 + list_for_each_entry_safe(action_tbl, p, cleanup, list_node) 295 + hws_action_ste_table_destroy(action_tbl); 296 + } 297 + 298 + static void hws_action_ste_pool_cleanup(struct work_struct *work) 299 + { 300 + enum mlx5hws_pool_optimize opt; 301 + struct mlx5hws_context *ctx; 302 + LIST_HEAD(cleanup); 303 + int i; 304 + 305 + ctx = container_of(work, struct mlx5hws_context, 306 + action_ste_cleanup.work); 307 + 308 + for (i = 0; i < ctx->queues; i++) { 309 + struct mlx5hws_action_ste_pool *p = &ctx->action_ste_pool[i]; 310 + 311 + mutex_lock(&p->lock); 312 + for (opt = MLX5HWS_POOL_OPTIMIZE_NONE; 313 + opt < MLX5HWS_POOL_OPTIMIZE_MAX; opt++) 314 + hws_action_ste_pool_element_collect_stale( 315 + &p->elems[opt], &cleanup); 316 + mutex_unlock(&p->lock); 317 + } 318 + 319 + hws_action_ste_table_cleanup_list(&cleanup); 320 + 321 + schedule_delayed_work(&ctx->action_ste_cleanup, 322 + secs_to_jiffies( 323 + MLX5HWS_ACTION_STE_POOL_CLEANUP_SECONDS)); 324 + } 325 + 326 + int mlx5hws_action_ste_pool_init(struct mlx5hws_context *ctx) 327 + { 328 + struct mlx5hws_action_ste_pool *pool; 329 + size_t queues = ctx->queues; 330 + int i, err; 331 + 332 + pool = kcalloc(queues, sizeof(*pool), GFP_KERNEL); 333 + if (!pool) 334 + return -ENOMEM; 335 + 336 + for (i = 0; i < queues; i++) { 337 + err = hws_action_ste_pool_init(ctx, &pool[i]); 338 + if (err) 339 + goto free_pool; 340 + } 341 + 342 + ctx->action_ste_pool = pool; 343 + 344 + INIT_DELAYED_WORK(&ctx->action_ste_cleanup, 345 + hws_action_ste_pool_cleanup); 346 + schedule_delayed_work( 347 + &ctx->action_ste_cleanup, 348 + secs_to_jiffies(MLX5HWS_ACTION_STE_POOL_CLEANUP_SECONDS)); 349 + 350 + return 0; 351 + 352 + free_pool: 353 + while (i--) 354 + hws_action_ste_pool_destroy(&pool[i]); 355 + kfree(pool); 356 + 357 + return err; 358 + } 359 + 360 + void mlx5hws_action_ste_pool_uninit(struct mlx5hws_context *ctx) 361 + { 362 + size_t queues = ctx->queues; 363 + int i; 364 + 365 + cancel_delayed_work_sync(&ctx->action_ste_cleanup); 366 + 367 + for (i = 0; i < queues; i++) 368 + hws_action_ste_pool_destroy(&ctx->action_ste_pool[i]); 369 + 370 + kfree(ctx->action_ste_pool); 371 + } 372 + 373 + static struct mlx5hws_action_ste_pool_element * 374 + hws_action_ste_choose_elem(struct mlx5hws_action_ste_pool *pool, 375 + bool skip_rx, bool skip_tx) 376 + { 377 + if (skip_rx) 378 + return &pool->elems[MLX5HWS_POOL_OPTIMIZE_MIRROR]; 379 + 380 + if (skip_tx) 381 + return &pool->elems[MLX5HWS_POOL_OPTIMIZE_ORIG]; 382 + 383 + return &pool->elems[MLX5HWS_POOL_OPTIMIZE_NONE]; 384 + } 385 + 386 + static int 387 + hws_action_ste_table_chunk_alloc(struct mlx5hws_action_ste_table *action_tbl, 388 + struct mlx5hws_action_ste_chunk *chunk) 389 + { 390 + int err; 391 + 392 + err = mlx5hws_pool_chunk_alloc(action_tbl->pool, &chunk->ste); 393 + if (err) 394 + return err; 395 + 396 + chunk->action_tbl = action_tbl; 397 + action_tbl->last_used = jiffies; 398 + 399 + return 0; 400 + } 401 + 402 + int mlx5hws_action_ste_chunk_alloc(struct mlx5hws_action_ste_pool *pool, 403 + bool skip_rx, bool skip_tx, 404 + struct mlx5hws_action_ste_chunk *chunk) 405 + { 406 + struct mlx5hws_action_ste_pool_element *elem; 407 + struct mlx5hws_action_ste_table *action_tbl; 408 + bool found; 409 + int err; 410 + 411 + if (skip_rx && skip_tx) 412 + return -EINVAL; 413 + 414 + mutex_lock(&pool->lock); 415 + 416 + elem = hws_action_ste_choose_elem(pool, skip_rx, skip_tx); 417 + 418 + mlx5hws_dbg(elem->ctx, 419 + "Allocating action STEs skip_rx %d skip_tx %d order %d\n", 420 + skip_rx, skip_tx, chunk->ste.order); 421 + 422 + found = false; 423 + list_for_each_entry(action_tbl, &elem->available, list_node) { 424 + if (!hws_action_ste_table_chunk_alloc(action_tbl, chunk)) { 425 + found = true; 426 + break; 427 + } 428 + } 429 + 430 + if (!found) { 431 + action_tbl = hws_action_ste_table_alloc(elem); 432 + if (IS_ERR(action_tbl)) { 433 + err = PTR_ERR(action_tbl); 434 + goto out; 435 + } 436 + 437 + err = hws_action_ste_table_chunk_alloc(action_tbl, chunk); 438 + if (err) 439 + goto out; 440 + } 441 + 442 + if (mlx5hws_pool_empty(action_tbl->pool)) 443 + list_move(&action_tbl->list_node, &elem->full); 444 + 445 + err = 0; 446 + 447 + out: 448 + mutex_unlock(&pool->lock); 449 + 450 + return err; 451 + } 452 + 453 + void mlx5hws_action_ste_chunk_free(struct mlx5hws_action_ste_chunk *chunk) 454 + { 455 + struct mutex *lock = &chunk->action_tbl->parent_elem->parent_pool->lock; 456 + 457 + mlx5hws_dbg(chunk->action_tbl->pool->ctx, 458 + "Freeing action STEs offset %d order %d\n", 459 + chunk->ste.offset, chunk->ste.order); 460 + 461 + mutex_lock(lock); 462 + mlx5hws_pool_chunk_free(chunk->action_tbl->pool, &chunk->ste); 463 + chunk->action_tbl->last_used = jiffies; 464 + list_move(&chunk->action_tbl->list_node, 465 + &chunk->action_tbl->parent_elem->available); 466 + mutex_unlock(lock); 467 + }
+69
drivers/net/ethernet/mellanox/mlx5/core/steering/hws/action_ste_pool.h
··· 1 + /* SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB */ 2 + /* Copyright (c) 2025 NVIDIA Corporation & Affiliates */ 3 + 4 + #ifndef ACTION_STE_POOL_H_ 5 + #define ACTION_STE_POOL_H_ 6 + 7 + #define MLX5HWS_ACTION_STE_TABLE_INIT_LOG_SZ 10 8 + #define MLX5HWS_ACTION_STE_TABLE_STEP_LOG_SZ 1 9 + #define MLX5HWS_ACTION_STE_TABLE_MAX_LOG_SZ 20 10 + 11 + #define MLX5HWS_ACTION_STE_POOL_CLEANUP_SECONDS 300 12 + #define MLX5HWS_ACTION_STE_POOL_EXPIRE_SECONDS 300 13 + 14 + struct mlx5hws_action_ste_pool_element; 15 + 16 + struct mlx5hws_action_ste_table { 17 + struct mlx5hws_action_ste_pool_element *parent_elem; 18 + /* Wraps the RTC and STE range for this given action. */ 19 + struct mlx5hws_pool *pool; 20 + /* Match STEs use this STC to jump to this pool's RTC. */ 21 + struct mlx5hws_pool_chunk stc; 22 + u32 rtc_0_id; 23 + u32 rtc_1_id; 24 + struct list_head list_node; 25 + unsigned long last_used; 26 + }; 27 + 28 + struct mlx5hws_action_ste_pool_element { 29 + struct mlx5hws_context *ctx; 30 + struct mlx5hws_action_ste_pool *parent_pool; 31 + size_t log_sz; /* Size of the largest table so far. */ 32 + enum mlx5hws_pool_optimize opt; 33 + struct list_head available; 34 + struct list_head full; 35 + }; 36 + 37 + /* Central repository of action STEs. The context contains one of these pools 38 + * per queue. 39 + */ 40 + struct mlx5hws_action_ste_pool { 41 + /* Protects the entire pool. We have one pool per queue and only one 42 + * operation can be active per rule at a given time. Thus this lock 43 + * protects solely against concurrent garbage collection and we expect 44 + * very little contention. 45 + */ 46 + struct mutex lock; 47 + struct mlx5hws_action_ste_pool_element elems[MLX5HWS_POOL_OPTIMIZE_MAX]; 48 + }; 49 + 50 + /* A chunk of STEs and the table it was allocated from. Used by rules. */ 51 + struct mlx5hws_action_ste_chunk { 52 + struct mlx5hws_action_ste_table *action_tbl; 53 + struct mlx5hws_pool_chunk ste; 54 + }; 55 + 56 + int mlx5hws_action_ste_pool_init(struct mlx5hws_context *ctx); 57 + 58 + void mlx5hws_action_ste_pool_uninit(struct mlx5hws_context *ctx); 59 + 60 + /* Callers are expected to fill chunk->ste.order. On success, this function 61 + * populates chunk->tbl and chunk->ste.offset. 62 + */ 63 + int mlx5hws_action_ste_chunk_alloc(struct mlx5hws_action_ste_pool *pool, 64 + bool skip_rx, bool skip_tx, 65 + struct mlx5hws_action_ste_chunk *chunk); 66 + 67 + void mlx5hws_action_ste_chunk_free(struct mlx5hws_action_ste_chunk *chunk); 68 + 69 + #endif /* ACTION_STE_POOL_H_ */
+34 -64
drivers/net/ethernet/mellanox/mlx5/core/steering/hws/bwc.c
··· 90 90 bwc_matcher->priority = priority; 91 91 bwc_matcher->size_log = MLX5HWS_BWC_MATCHER_INIT_SIZE_LOG; 92 92 93 + bwc_matcher->size_of_at_array = MLX5HWS_BWC_MATCHER_ATTACH_AT_NUM; 94 + bwc_matcher->at = kcalloc(bwc_matcher->size_of_at_array, 95 + sizeof(*bwc_matcher->at), GFP_KERNEL); 96 + if (!bwc_matcher->at) 97 + goto free_bwc_matcher_rules; 98 + 93 99 /* create dummy action template */ 94 100 bwc_matcher->at[0] = 95 101 mlx5hws_action_template_create(action_types ? 96 102 action_types : init_action_types); 97 103 if (!bwc_matcher->at[0]) { 98 104 mlx5hws_err(table->ctx, "BWC matcher: failed creating action template\n"); 99 - goto free_bwc_matcher_rules; 105 + goto free_bwc_matcher_at_array; 100 106 } 101 107 102 108 bwc_matcher->num_of_at = 1; ··· 132 126 mlx5hws_match_template_destroy(bwc_matcher->mt); 133 127 free_at: 134 128 mlx5hws_action_template_destroy(bwc_matcher->at[0]); 129 + free_bwc_matcher_at_array: 130 + kfree(bwc_matcher->at); 135 131 free_bwc_matcher_rules: 136 132 kfree(bwc_matcher->rules); 137 133 err: ··· 200 192 201 193 for (i = 0; i < bwc_matcher->num_of_at; i++) 202 194 mlx5hws_action_template_destroy(bwc_matcher->at[i]); 195 + kfree(bwc_matcher->at); 203 196 204 197 mlx5hws_match_template_destroy(bwc_matcher->mt); 205 198 kfree(bwc_matcher->rules); ··· 478 469 struct mlx5hws_cmd_query_caps *caps = bwc_matcher->matcher->tbl->ctx->caps; 479 470 480 471 /* check the match RTC size */ 481 - if ((bwc_matcher->size_log + 482 - MLX5HWS_MATCHER_ASSURED_MAIN_TBL_DEPTH + 483 - MLX5HWS_BWC_MATCHER_SIZE_LOG_STEP) > 484 - (caps->ste_alloc_log_max - 1)) 485 - return true; 486 - 487 - /* check the action RTC size */ 488 - if ((bwc_matcher->size_log + 489 - MLX5HWS_BWC_MATCHER_SIZE_LOG_STEP + 490 - ilog2(roundup_pow_of_two(bwc_matcher->matcher->action_ste.max_stes)) + 491 - MLX5HWS_MATCHER_ACTION_RTC_UPDATE_MULT) > 492 - (caps->ste_alloc_log_max - 1)) 493 - return true; 494 - 495 - return false; 472 + return (bwc_matcher->size_log + MLX5HWS_MATCHER_ASSURED_MAIN_TBL_DEPTH + 473 + MLX5HWS_BWC_MATCHER_SIZE_LOG_STEP) > 474 + (caps->ste_alloc_log_max - 1); 496 475 } 497 476 498 477 static bool ··· 517 520 struct mlx5hws_rule_action rule_actions[]) 518 521 { 519 522 enum mlx5hws_action_type action_types[MLX5HWS_BWC_MAX_ACTS]; 523 + void *p; 524 + 525 + if (unlikely(bwc_matcher->num_of_at >= bwc_matcher->size_of_at_array)) { 526 + if (bwc_matcher->size_of_at_array >= MLX5HWS_MATCHER_MAX_AT) 527 + return -ENOMEM; 528 + bwc_matcher->size_of_at_array *= 2; 529 + p = krealloc(bwc_matcher->at, 530 + bwc_matcher->size_of_at_array * 531 + sizeof(*bwc_matcher->at), 532 + __GFP_ZERO | GFP_KERNEL); 533 + if (!p) { 534 + bwc_matcher->size_of_at_array /= 2; 535 + return -ENOMEM; 536 + } 537 + 538 + bwc_matcher->at = p; 539 + } 520 540 521 541 hws_bwc_rule_actions_to_action_types(rule_actions, action_types); 522 542 ··· 767 753 return hws_bwc_matcher_move(bwc_matcher); 768 754 } 769 755 770 - static int 771 - hws_bwc_matcher_rehash_at(struct mlx5hws_bwc_matcher *bwc_matcher) 772 - { 773 - /* Rehash by action template doesn't require any additional checking. 774 - * The bwc_matcher already contains the new action template. 775 - * Just do the usual rehash: 776 - * - create new matcher 777 - * - move all the rules to the new matcher 778 - * - destroy the old matcher 779 - */ 780 - return hws_bwc_matcher_move(bwc_matcher); 781 - } 782 - 783 756 int mlx5hws_bwc_rule_create_simple(struct mlx5hws_bwc_rule *bwc_rule, 784 757 u32 *match_param, 785 758 struct mlx5hws_rule_action rule_actions[], ··· 806 805 ret = mlx5hws_matcher_attach_at(bwc_matcher->matcher, 807 806 bwc_matcher->at[at_idx]); 808 807 if (unlikely(ret)) { 809 - /* Action template attach failed, possibly due to 810 - * requiring more action STEs. 811 - * Need to attempt creating new matcher with all 812 - * the action templates, including the new one. 813 - */ 814 - ret = hws_bwc_matcher_rehash_at(bwc_matcher); 815 - if (unlikely(ret)) { 816 - mlx5hws_action_template_destroy(bwc_matcher->at[at_idx]); 817 - bwc_matcher->at[at_idx] = NULL; 818 - bwc_matcher->num_of_at--; 819 - 820 - hws_bwc_unlock_all_queues(ctx); 821 - 822 - mlx5hws_err(ctx, 823 - "BWC rule insertion: rehash AT failed (%d)\n", ret); 824 - return ret; 825 - } 808 + hws_bwc_unlock_all_queues(ctx); 809 + return ret; 826 810 } 827 811 828 812 hws_bwc_unlock_all_queues(ctx); ··· 961 975 ret = mlx5hws_matcher_attach_at(bwc_matcher->matcher, 962 976 bwc_matcher->at[at_idx]); 963 977 if (unlikely(ret)) { 964 - /* Action template attach failed, possibly due to 965 - * requiring more action STEs. 966 - * Need to attempt creating new matcher with all 967 - * the action templates, including the new one. 968 - */ 969 - ret = hws_bwc_matcher_rehash_at(bwc_matcher); 970 - if (unlikely(ret)) { 971 - mlx5hws_action_template_destroy(bwc_matcher->at[at_idx]); 972 - bwc_matcher->at[at_idx] = NULL; 973 - bwc_matcher->num_of_at--; 974 - 975 - hws_bwc_unlock_all_queues(ctx); 976 - 977 - mlx5hws_err(ctx, 978 - "BWC rule update: rehash AT failed (%d)\n", 979 - ret); 980 - return ret; 981 - } 978 + hws_bwc_unlock_all_queues(ctx); 979 + return ret; 982 980 } 983 981 } 984 982
+4 -5
drivers/net/ethernet/mellanox/mlx5/core/steering/hws/bwc.h
··· 10 10 #define MLX5HWS_BWC_MATCHER_REHASH_BURST_TH 32 11 11 12 12 /* Max number of AT attach operations for the same matcher. 13 - * When the limit is reached, next attempt to attach new AT 14 - * will result in creation of a new matcher and moving all 15 - * the rules to this matcher. 13 + * When the limit is reached, a larger buffer is allocated for the ATs. 16 14 */ 17 15 #define MLX5HWS_BWC_MATCHER_ATTACH_AT_NUM 8 18 16 ··· 21 23 struct mlx5hws_bwc_matcher { 22 24 struct mlx5hws_matcher *matcher; 23 25 struct mlx5hws_match_template *mt; 24 - struct mlx5hws_action_template *at[MLX5HWS_BWC_MATCHER_ATTACH_AT_NUM]; 25 - u32 priority; 26 + struct mlx5hws_action_template **at; 26 27 u8 num_of_at; 28 + u8 size_of_at_array; 27 29 u8 size_log; 30 + u32 priority; 28 31 atomic_t num_of_rules; 29 32 struct list_head *rules; 30 33 };
-1
drivers/net/ethernet/mellanox/mlx5/core/steering/hws/cmd.c
··· 406 406 MLX5_SET(rtc, attr, match_definer_1, rtc_attr->match_definer_1); 407 407 MLX5_SET(rtc, attr, stc_id, rtc_attr->stc_base); 408 408 MLX5_SET(rtc, attr, ste_table_base_id, rtc_attr->ste_base); 409 - MLX5_SET(rtc, attr, ste_table_offset, rtc_attr->ste_offset); 410 409 MLX5_SET(rtc, attr, miss_flow_table_id, rtc_attr->miss_ft_id); 411 410 MLX5_SET(rtc, attr, reparse_mode, rtc_attr->reparse_mode); 412 411
-1
drivers/net/ethernet/mellanox/mlx5/core/steering/hws/cmd.h
··· 70 70 u32 pd; 71 71 u32 stc_base; 72 72 u32 ste_base; 73 - u32 ste_offset; 74 73 u32 miss_ft_id; 75 74 bool fw_gen_wqe; 76 75 u8 update_index_mode;
+7 -1
drivers/net/ethernet/mellanox/mlx5/core/steering/hws/context.c
··· 34 34 35 35 /* Create an STC pool per FT type */ 36 36 pool_attr.pool_type = MLX5HWS_POOL_TYPE_STC; 37 - pool_attr.flags = MLX5HWS_POOL_FLAGS_FOR_STC_POOL; 38 37 max_log_sz = min(MLX5HWS_POOL_STC_LOG_SZ, ctx->caps->stc_alloc_log_max); 39 38 pool_attr.alloc_log_sz = max(max_log_sz, ctx->caps->stc_alloc_log_gran); 40 39 ··· 158 159 if (ret) 159 160 goto pools_uninit; 160 161 162 + ret = mlx5hws_action_ste_pool_init(ctx); 163 + if (ret) 164 + goto close_queues; 165 + 161 166 INIT_LIST_HEAD(&ctx->tbl_list); 162 167 163 168 return 0; 164 169 170 + close_queues: 171 + mlx5hws_send_queues_close(ctx); 165 172 pools_uninit: 166 173 hws_context_pools_uninit(ctx); 167 174 uninit_pd: ··· 180 175 if (!(ctx->flags & MLX5HWS_CONTEXT_FLAG_HWS_SUPPORT)) 181 176 return; 182 177 178 + mlx5hws_action_ste_pool_uninit(ctx); 183 179 mlx5hws_send_queues_close(ctx); 184 180 hws_context_pools_uninit(ctx); 185 181 hws_context_uninit_pd(ctx);
+2
drivers/net/ethernet/mellanox/mlx5/core/steering/hws/context.h
··· 39 39 struct mlx5hws_cmd_query_caps *caps; 40 40 u32 pd_num; 41 41 struct mlx5hws_pool *stc_pool; 42 + struct mlx5hws_action_ste_pool *action_ste_pool; /* One per queue */ 43 + struct delayed_work action_ste_cleanup; 42 44 struct mlx5hws_context_common_res common_res; 43 45 struct mlx5hws_pattern_cache *pattern_cache; 44 46 struct mlx5hws_definer_cache *definer_cache;
+45 -26
drivers/net/ethernet/mellanox/mlx5/core/steering/hws/debug.c
··· 118 118 { 119 119 enum mlx5hws_table_type tbl_type = matcher->tbl->type; 120 120 struct mlx5hws_cmd_ft_query_attr ft_attr = {0}; 121 - struct mlx5hws_pool_chunk *ste; 122 121 struct mlx5hws_pool *ste_pool; 123 122 u64 icm_addr_0 = 0; 124 123 u64 icm_addr_1 = 0; ··· 133 134 matcher->end_ft_id, 134 135 matcher->col_matcher ? HWS_PTR_TO_ID(matcher->col_matcher) : 0); 135 136 136 - ste = &matcher->match_ste.ste; 137 137 ste_pool = matcher->match_ste.pool; 138 138 if (ste_pool) { 139 - ste_0_id = mlx5hws_pool_chunk_get_base_id(ste_pool, ste); 139 + ste_0_id = mlx5hws_pool_get_base_id(ste_pool); 140 140 if (tbl_type == MLX5HWS_TABLE_TYPE_FDB) 141 - ste_1_id = mlx5hws_pool_chunk_get_base_mirror_id(ste_pool, ste); 141 + ste_1_id = mlx5hws_pool_get_base_mirror_id(ste_pool); 142 142 } 143 143 144 144 seq_printf(f, ",%d,%d,%d,%d", ··· 145 147 (int)ste_0_id, 146 148 matcher->match_ste.rtc_1_id, 147 149 (int)ste_1_id); 148 - 149 - ste = &matcher->action_ste.ste; 150 - ste_pool = matcher->action_ste.pool; 151 - if (ste_pool) { 152 - ste_0_id = mlx5hws_pool_chunk_get_base_id(ste_pool, ste); 153 - if (tbl_type == MLX5HWS_TABLE_TYPE_FDB) 154 - ste_1_id = mlx5hws_pool_chunk_get_base_mirror_id(ste_pool, ste); 155 - else 156 - ste_1_id = -1; 157 - } else { 158 - ste_0_id = -1; 159 - ste_1_id = -1; 160 - } 161 150 162 151 ft_attr.type = matcher->tbl->fw_ft_type; 163 152 ret = mlx5hws_cmd_flow_table_query(matcher->tbl->ctx->mdev, ··· 155 170 if (ret) 156 171 return ret; 157 172 158 - seq_printf(f, ",%d,%d,%d,%d,%d,0x%llx,0x%llx\n", 159 - matcher->action_ste.rtc_0_id, (int)ste_0_id, 160 - matcher->action_ste.rtc_1_id, (int)ste_1_id, 161 - 0, 173 + seq_printf(f, ",-1,-1,-1,-1,0,0x%llx,0x%llx\n", 162 174 mlx5hws_debug_icm_to_idx(icm_addr_0), 163 175 mlx5hws_debug_icm_to_idx(icm_addr_1)); 164 176 ··· 369 387 if (!stc_pool) 370 388 return 0; 371 389 372 - if (stc_pool->resource[0]) { 373 - ret = hws_debug_dump_context_stc_resource(f, ctx, stc_pool->resource[0]); 390 + if (stc_pool->resource) { 391 + ret = hws_debug_dump_context_stc_resource(f, ctx, 392 + stc_pool->resource); 374 393 if (ret) 375 394 return ret; 376 395 } 377 396 378 - if (stc_pool->mirror_resource[0]) { 379 - ret = hws_debug_dump_context_stc_resource(f, ctx, stc_pool->mirror_resource[0]); 397 + if (stc_pool->mirror_resource) { 398 + struct mlx5hws_pool_resource *res = stc_pool->mirror_resource; 399 + 400 + ret = hws_debug_dump_context_stc_resource(f, ctx, res); 380 401 if (ret) 381 402 return ret; 382 403 } ··· 387 402 return 0; 388 403 } 389 404 405 + static void 406 + hws_debug_dump_action_ste_table(struct seq_file *f, 407 + struct mlx5hws_action_ste_table *action_tbl) 408 + { 409 + int ste_0_id = mlx5hws_pool_get_base_id(action_tbl->pool); 410 + int ste_1_id = mlx5hws_pool_get_base_mirror_id(action_tbl->pool); 411 + 412 + seq_printf(f, "%d,0x%llx,%d,%d,%d,%d\n", 413 + MLX5HWS_DEBUG_RES_TYPE_ACTION_STE_TABLE, 414 + HWS_PTR_TO_ID(action_tbl), 415 + action_tbl->rtc_0_id, ste_0_id, 416 + action_tbl->rtc_1_id, ste_1_id); 417 + } 418 + 419 + static void hws_debug_dump_action_ste_pool(struct seq_file *f, 420 + struct mlx5hws_action_ste_pool *pool) 421 + { 422 + struct mlx5hws_action_ste_table *action_tbl; 423 + enum mlx5hws_pool_optimize opt; 424 + 425 + mutex_lock(&pool->lock); 426 + for (opt = MLX5HWS_POOL_OPTIMIZE_NONE; opt < MLX5HWS_POOL_OPTIMIZE_MAX; 427 + opt++) { 428 + list_for_each_entry(action_tbl, &pool->elems[opt].available, 429 + list_node) { 430 + hws_debug_dump_action_ste_table(f, action_tbl); 431 + } 432 + } 433 + mutex_unlock(&pool->lock); 434 + } 435 + 390 436 static int hws_debug_dump_context(struct seq_file *f, struct mlx5hws_context *ctx) 391 437 { 392 438 struct mlx5hws_table *tbl; 393 - int ret; 439 + int ret, i; 394 440 395 441 ret = hws_debug_dump_context_info(f, ctx); 396 442 if (ret) ··· 440 424 if (ret) 441 425 return ret; 442 426 } 427 + 428 + for (i = 0; i < ctx->queues; i++) 429 + hws_debug_dump_action_ste_pool(f, &ctx->action_ste_pool[i]); 443 430 444 431 return 0; 445 432 }
+2
drivers/net/ethernet/mellanox/mlx5/core/steering/hws/debug.h
··· 26 26 MLX5HWS_DEBUG_RES_TYPE_MATCHER_TEMPLATE_HASH_DEFINER = 4205, 27 27 MLX5HWS_DEBUG_RES_TYPE_MATCHER_TEMPLATE_RANGE_DEFINER = 4206, 28 28 MLX5HWS_DEBUG_RES_TYPE_MATCHER_TEMPLATE_COMPARE_MATCH_DEFINER = 4207, 29 + 30 + MLX5HWS_DEBUG_RES_TYPE_ACTION_STE_TABLE = 4300, 29 31 }; 30 32 31 33 static inline u64
+1
drivers/net/ethernet/mellanox/mlx5/core/steering/hws/internal.h
··· 17 17 #include "context.h" 18 18 #include "table.h" 19 19 #include "send.h" 20 + #include "action_ste_pool.h" 20 21 #include "rule.h" 21 22 #include "cmd.h" 22 23 #include "action.h"
+95 -319
drivers/net/ethernet/mellanox/mlx5/core/steering/hws/matcher.c
··· 3 3 4 4 #include "internal.h" 5 5 6 - enum mlx5hws_matcher_rtc_type { 7 - HWS_MATCHER_RTC_TYPE_MATCH, 8 - HWS_MATCHER_RTC_TYPE_STE_ARRAY, 9 - HWS_MATCHER_RTC_TYPE_MAX, 10 - }; 11 - 12 - static const char * const mlx5hws_matcher_rtc_type_str[] = { 13 - [HWS_MATCHER_RTC_TYPE_MATCH] = "MATCH", 14 - [HWS_MATCHER_RTC_TYPE_STE_ARRAY] = "STE_ARRAY", 15 - [HWS_MATCHER_RTC_TYPE_MAX] = "UNKNOWN", 16 - }; 17 - 18 - static const char *hws_matcher_rtc_type_to_str(enum mlx5hws_matcher_rtc_type rtc_type) 19 - { 20 - if (rtc_type > HWS_MATCHER_RTC_TYPE_MAX) 21 - rtc_type = HWS_MATCHER_RTC_TYPE_MAX; 22 - return mlx5hws_matcher_rtc_type_str[rtc_type]; 23 - } 24 - 25 6 static bool hws_matcher_requires_col_tbl(u8 log_num_of_rules) 26 7 { 27 8 /* Collision table concatenation is done only for large rule tables */ ··· 178 197 179 198 static void hws_matcher_set_rtc_attr_sz(struct mlx5hws_matcher *matcher, 180 199 struct mlx5hws_cmd_rtc_create_attr *rtc_attr, 181 - enum mlx5hws_matcher_rtc_type rtc_type, 182 200 bool is_mirror) 183 201 { 184 - struct mlx5hws_pool_chunk *ste = &matcher->action_ste.ste; 185 202 enum mlx5hws_matcher_flow_src flow_src = matcher->attr.optimize_flow_src; 186 - bool is_match_rtc = rtc_type == HWS_MATCHER_RTC_TYPE_MATCH; 187 203 188 204 if ((flow_src == MLX5HWS_MATCHER_FLOW_SRC_VPORT && !is_mirror) || 189 205 (flow_src == MLX5HWS_MATCHER_FLOW_SRC_WIRE && is_mirror)) { 190 206 /* Optimize FDB RTC */ 191 207 rtc_attr->log_size = 0; 192 208 rtc_attr->log_depth = 0; 193 - } else { 194 - /* Keep original values */ 195 - rtc_attr->log_size = is_match_rtc ? matcher->attr.table.sz_row_log : ste->order; 196 - rtc_attr->log_depth = is_match_rtc ? matcher->attr.table.sz_col_log : 0; 197 209 } 198 210 } 199 211 200 - static int hws_matcher_create_rtc(struct mlx5hws_matcher *matcher, 201 - enum mlx5hws_matcher_rtc_type rtc_type) 212 + static int hws_matcher_create_rtc(struct mlx5hws_matcher *matcher) 202 213 { 203 214 struct mlx5hws_matcher_attr *attr = &matcher->attr; 204 215 struct mlx5hws_cmd_rtc_create_attr rtc_attr = {0}; 205 216 struct mlx5hws_match_template *mt = matcher->mt; 206 217 struct mlx5hws_context *ctx = matcher->tbl->ctx; 207 - struct mlx5hws_action_default_stc *default_stc; 208 - struct mlx5hws_matcher_action_ste *action_ste; 209 218 struct mlx5hws_table *tbl = matcher->tbl; 210 - struct mlx5hws_pool *ste_pool, *stc_pool; 211 - struct mlx5hws_pool_chunk *ste; 212 - u32 *rtc_0_id, *rtc_1_id; 213 219 u32 obj_id; 214 220 int ret; 215 221 216 - switch (rtc_type) { 217 - case HWS_MATCHER_RTC_TYPE_MATCH: 218 - rtc_0_id = &matcher->match_ste.rtc_0_id; 219 - rtc_1_id = &matcher->match_ste.rtc_1_id; 220 - ste_pool = matcher->match_ste.pool; 221 - ste = &matcher->match_ste.ste; 222 - ste->order = attr->table.sz_col_log + attr->table.sz_row_log; 222 + rtc_attr.log_size = attr->table.sz_row_log; 223 + rtc_attr.log_depth = attr->table.sz_col_log; 224 + rtc_attr.is_frst_jumbo = mlx5hws_matcher_mt_is_jumbo(mt); 225 + rtc_attr.is_scnd_range = 0; 226 + rtc_attr.miss_ft_id = matcher->end_ft_id; 223 227 224 - rtc_attr.log_size = attr->table.sz_row_log; 225 - rtc_attr.log_depth = attr->table.sz_col_log; 226 - rtc_attr.is_frst_jumbo = mlx5hws_matcher_mt_is_jumbo(mt); 227 - rtc_attr.is_scnd_range = 0; 228 - rtc_attr.miss_ft_id = matcher->end_ft_id; 228 + if (attr->insert_mode == MLX5HWS_MATCHER_INSERT_BY_HASH) { 229 + /* The usual Hash Table */ 230 + rtc_attr.update_index_mode = 231 + MLX5_IFC_RTC_STE_UPDATE_MODE_BY_HASH; 229 232 230 - if (attr->insert_mode == MLX5HWS_MATCHER_INSERT_BY_HASH) { 231 - /* The usual Hash Table */ 232 - rtc_attr.update_index_mode = MLX5_IFC_RTC_STE_UPDATE_MODE_BY_HASH; 233 + /* The first mt is used since all share the same definer */ 234 + rtc_attr.match_definer_0 = mlx5hws_definer_get_id(mt->definer); 235 + } else if (attr->insert_mode == MLX5HWS_MATCHER_INSERT_BY_INDEX) { 236 + rtc_attr.update_index_mode = 237 + MLX5_IFC_RTC_STE_UPDATE_MODE_BY_OFFSET; 238 + rtc_attr.num_hash_definer = 1; 233 239 234 - /* The first mt is used since all share the same definer */ 235 - rtc_attr.match_definer_0 = mlx5hws_definer_get_id(mt->definer); 236 - } else if (attr->insert_mode == MLX5HWS_MATCHER_INSERT_BY_INDEX) { 237 - rtc_attr.update_index_mode = MLX5_IFC_RTC_STE_UPDATE_MODE_BY_OFFSET; 238 - rtc_attr.num_hash_definer = 1; 239 - 240 - if (attr->distribute_mode == MLX5HWS_MATCHER_DISTRIBUTE_BY_HASH) { 241 - /* Hash Split Table */ 242 - rtc_attr.access_index_mode = MLX5_IFC_RTC_STE_ACCESS_MODE_BY_HASH; 243 - rtc_attr.match_definer_0 = mlx5hws_definer_get_id(mt->definer); 244 - } else if (attr->distribute_mode == MLX5HWS_MATCHER_DISTRIBUTE_BY_LINEAR) { 245 - /* Linear Lookup Table */ 246 - rtc_attr.access_index_mode = MLX5_IFC_RTC_STE_ACCESS_MODE_LINEAR; 247 - rtc_attr.match_definer_0 = ctx->caps->linear_match_definer; 248 - } 240 + if (attr->distribute_mode == 241 + MLX5HWS_MATCHER_DISTRIBUTE_BY_HASH) { 242 + /* Hash Split Table */ 243 + rtc_attr.access_index_mode = 244 + MLX5_IFC_RTC_STE_ACCESS_MODE_BY_HASH; 245 + rtc_attr.match_definer_0 = 246 + mlx5hws_definer_get_id(mt->definer); 247 + } else if (attr->distribute_mode == 248 + MLX5HWS_MATCHER_DISTRIBUTE_BY_LINEAR) { 249 + /* Linear Lookup Table */ 250 + rtc_attr.access_index_mode = 251 + MLX5_IFC_RTC_STE_ACCESS_MODE_LINEAR; 252 + rtc_attr.match_definer_0 = 253 + ctx->caps->linear_match_definer; 249 254 } 250 - 251 - /* Match pool requires implicit allocation */ 252 - ret = mlx5hws_pool_chunk_alloc(ste_pool, ste); 253 - if (ret) { 254 - mlx5hws_err(ctx, "Failed to allocate STE for %s RTC", 255 - hws_matcher_rtc_type_to_str(rtc_type)); 256 - return ret; 257 - } 258 - break; 259 - 260 - case HWS_MATCHER_RTC_TYPE_STE_ARRAY: 261 - action_ste = &matcher->action_ste; 262 - 263 - rtc_0_id = &action_ste->rtc_0_id; 264 - rtc_1_id = &action_ste->rtc_1_id; 265 - ste_pool = action_ste->pool; 266 - ste = &action_ste->ste; 267 - /* Action RTC size calculation: 268 - * log((max number of rules in matcher) * 269 - * (max number of action STEs per rule) * 270 - * (2 to support writing new STEs for update rule)) 271 - */ 272 - ste->order = ilog2(roundup_pow_of_two(action_ste->max_stes)) + 273 - attr->table.sz_row_log + 274 - MLX5HWS_MATCHER_ACTION_RTC_UPDATE_MULT; 275 - rtc_attr.log_size = ste->order; 276 - rtc_attr.log_depth = 0; 277 - rtc_attr.update_index_mode = MLX5_IFC_RTC_STE_UPDATE_MODE_BY_OFFSET; 278 - /* The action STEs use the default always hit definer */ 279 - rtc_attr.match_definer_0 = ctx->caps->trivial_match_definer; 280 - rtc_attr.is_frst_jumbo = false; 281 - rtc_attr.miss_ft_id = 0; 282 - break; 283 - 284 - default: 285 - mlx5hws_err(ctx, "HWS Invalid RTC type\n"); 286 - return -EINVAL; 287 255 } 288 256 289 - obj_id = mlx5hws_pool_chunk_get_base_id(ste_pool, ste); 257 + obj_id = mlx5hws_pool_get_base_id(matcher->match_ste.pool); 290 258 291 259 rtc_attr.pd = ctx->pd_num; 292 260 rtc_attr.ste_base = obj_id; 293 - rtc_attr.ste_offset = ste->offset; 294 261 rtc_attr.reparse_mode = mlx5hws_context_get_reparse_mode(ctx); 295 262 rtc_attr.table_type = mlx5hws_table_get_res_fw_ft_type(tbl->type, false); 296 - hws_matcher_set_rtc_attr_sz(matcher, &rtc_attr, rtc_type, false); 263 + hws_matcher_set_rtc_attr_sz(matcher, &rtc_attr, false); 297 264 298 265 /* STC is a single resource (obj_id), use any STC for the ID */ 299 - stc_pool = ctx->stc_pool; 300 - default_stc = ctx->common_res.default_stc; 301 - obj_id = mlx5hws_pool_chunk_get_base_id(stc_pool, &default_stc->default_hit); 266 + obj_id = mlx5hws_pool_get_base_id(ctx->stc_pool); 302 267 rtc_attr.stc_base = obj_id; 303 268 304 - ret = mlx5hws_cmd_rtc_create(ctx->mdev, &rtc_attr, rtc_0_id); 269 + ret = mlx5hws_cmd_rtc_create(ctx->mdev, &rtc_attr, 270 + &matcher->match_ste.rtc_0_id); 305 271 if (ret) { 306 - mlx5hws_err(ctx, "Failed to create matcher RTC of type %s", 307 - hws_matcher_rtc_type_to_str(rtc_type)); 308 - goto free_ste; 272 + mlx5hws_err(ctx, "Failed to create matcher RTC\n"); 273 + return ret; 309 274 } 310 275 311 276 if (tbl->type == MLX5HWS_TABLE_TYPE_FDB) { 312 - obj_id = mlx5hws_pool_chunk_get_base_mirror_id(ste_pool, ste); 277 + obj_id = mlx5hws_pool_get_base_mirror_id( 278 + matcher->match_ste.pool); 313 279 rtc_attr.ste_base = obj_id; 314 280 rtc_attr.table_type = mlx5hws_table_get_res_fw_ft_type(tbl->type, true); 315 281 316 - obj_id = mlx5hws_pool_chunk_get_base_mirror_id(stc_pool, &default_stc->default_hit); 282 + obj_id = mlx5hws_pool_get_base_mirror_id(ctx->stc_pool); 317 283 rtc_attr.stc_base = obj_id; 318 - hws_matcher_set_rtc_attr_sz(matcher, &rtc_attr, rtc_type, true); 284 + hws_matcher_set_rtc_attr_sz(matcher, &rtc_attr, true); 319 285 320 - ret = mlx5hws_cmd_rtc_create(ctx->mdev, &rtc_attr, rtc_1_id); 286 + ret = mlx5hws_cmd_rtc_create(ctx->mdev, &rtc_attr, 287 + &matcher->match_ste.rtc_1_id); 321 288 if (ret) { 322 - mlx5hws_err(ctx, "Failed to create peer matcher RTC of type %s", 323 - hws_matcher_rtc_type_to_str(rtc_type)); 289 + mlx5hws_err(ctx, "Failed to create mirror matcher RTC\n"); 324 290 goto destroy_rtc_0; 325 291 } 326 292 } ··· 275 347 return 0; 276 348 277 349 destroy_rtc_0: 278 - mlx5hws_cmd_rtc_destroy(ctx->mdev, *rtc_0_id); 279 - free_ste: 280 - if (rtc_type == HWS_MATCHER_RTC_TYPE_MATCH) 281 - mlx5hws_pool_chunk_free(ste_pool, ste); 350 + mlx5hws_cmd_rtc_destroy(ctx->mdev, matcher->match_ste.rtc_0_id); 282 351 return ret; 283 352 } 284 353 285 - static void hws_matcher_destroy_rtc(struct mlx5hws_matcher *matcher, 286 - enum mlx5hws_matcher_rtc_type rtc_type) 354 + static void hws_matcher_destroy_rtc(struct mlx5hws_matcher *matcher) 287 355 { 288 - struct mlx5hws_matcher_action_ste *action_ste; 289 - struct mlx5hws_table *tbl = matcher->tbl; 290 - struct mlx5hws_pool_chunk *ste; 291 - struct mlx5hws_pool *ste_pool; 292 - u32 rtc_0_id, rtc_1_id; 356 + struct mlx5_core_dev *mdev = matcher->tbl->ctx->mdev; 293 357 294 - switch (rtc_type) { 295 - case HWS_MATCHER_RTC_TYPE_MATCH: 296 - rtc_0_id = matcher->match_ste.rtc_0_id; 297 - rtc_1_id = matcher->match_ste.rtc_1_id; 298 - ste_pool = matcher->match_ste.pool; 299 - ste = &matcher->match_ste.ste; 300 - break; 301 - case HWS_MATCHER_RTC_TYPE_STE_ARRAY: 302 - action_ste = &matcher->action_ste; 303 - rtc_0_id = action_ste->rtc_0_id; 304 - rtc_1_id = action_ste->rtc_1_id; 305 - ste_pool = action_ste->pool; 306 - ste = &action_ste->ste; 307 - break; 308 - default: 309 - return; 310 - } 358 + if (matcher->tbl->type == MLX5HWS_TABLE_TYPE_FDB) 359 + mlx5hws_cmd_rtc_destroy(mdev, matcher->match_ste.rtc_1_id); 311 360 312 - if (tbl->type == MLX5HWS_TABLE_TYPE_FDB) 313 - mlx5hws_cmd_rtc_destroy(matcher->tbl->ctx->mdev, rtc_1_id); 314 - 315 - mlx5hws_cmd_rtc_destroy(matcher->tbl->ctx->mdev, rtc_0_id); 316 - if (rtc_type == HWS_MATCHER_RTC_TYPE_MATCH) 317 - mlx5hws_pool_chunk_free(ste_pool, ste); 361 + mlx5hws_cmd_rtc_destroy(mdev, matcher->match_ste.rtc_0_id); 318 362 } 319 363 320 364 static int ··· 354 454 return 0; 355 455 } 356 456 357 - static int hws_matcher_resize_init(struct mlx5hws_matcher *src_matcher) 358 - { 359 - struct mlx5hws_matcher_resize_data *resize_data; 360 - 361 - resize_data = kzalloc(sizeof(*resize_data), GFP_KERNEL); 362 - if (!resize_data) 363 - return -ENOMEM; 364 - 365 - resize_data->max_stes = src_matcher->action_ste.max_stes; 366 - 367 - resize_data->stc = src_matcher->action_ste.stc; 368 - resize_data->rtc_0_id = src_matcher->action_ste.rtc_0_id; 369 - resize_data->rtc_1_id = src_matcher->action_ste.rtc_1_id; 370 - resize_data->pool = src_matcher->action_ste.max_stes ? 371 - src_matcher->action_ste.pool : NULL; 372 - 373 - /* Place the new resized matcher on the dst matcher's list */ 374 - list_add(&resize_data->list_node, &src_matcher->resize_dst->resize_data); 375 - 376 - /* Move all the previous resized matchers to the dst matcher's list */ 377 - while (!list_empty(&src_matcher->resize_data)) { 378 - resize_data = list_first_entry(&src_matcher->resize_data, 379 - struct mlx5hws_matcher_resize_data, 380 - list_node); 381 - list_del_init(&resize_data->list_node); 382 - list_add(&resize_data->list_node, &src_matcher->resize_dst->resize_data); 383 - } 384 - 385 - return 0; 386 - } 387 - 388 - static void hws_matcher_resize_uninit(struct mlx5hws_matcher *matcher) 389 - { 390 - struct mlx5hws_matcher_resize_data *resize_data; 391 - 392 - if (!mlx5hws_matcher_is_resizable(matcher)) 393 - return; 394 - 395 - while (!list_empty(&matcher->resize_data)) { 396 - resize_data = list_first_entry(&matcher->resize_data, 397 - struct mlx5hws_matcher_resize_data, 398 - list_node); 399 - list_del_init(&resize_data->list_node); 400 - 401 - if (resize_data->max_stes) { 402 - mlx5hws_action_free_single_stc(matcher->tbl->ctx, 403 - matcher->tbl->type, 404 - &resize_data->stc); 405 - 406 - if (matcher->tbl->type == MLX5HWS_TABLE_TYPE_FDB) 407 - mlx5hws_cmd_rtc_destroy(matcher->tbl->ctx->mdev, 408 - resize_data->rtc_1_id); 409 - 410 - mlx5hws_cmd_rtc_destroy(matcher->tbl->ctx->mdev, 411 - resize_data->rtc_0_id); 412 - 413 - if (resize_data->pool) 414 - mlx5hws_pool_destroy(resize_data->pool); 415 - } 416 - 417 - kfree(resize_data); 418 - } 419 - } 420 - 421 457 static int hws_matcher_bind_at(struct mlx5hws_matcher *matcher) 422 458 { 423 459 bool is_jumbo = mlx5hws_matcher_mt_is_jumbo(matcher->mt); 424 - struct mlx5hws_cmd_stc_modify_attr stc_attr = {0}; 425 - struct mlx5hws_matcher_action_ste *action_ste; 426 - struct mlx5hws_table *tbl = matcher->tbl; 427 - struct mlx5hws_pool_attr pool_attr = {0}; 428 - struct mlx5hws_context *ctx = tbl->ctx; 429 - u32 required_stes; 430 - u8 max_stes = 0; 460 + struct mlx5hws_context *ctx = matcher->tbl->ctx; 461 + u8 required_stes, max_stes; 431 462 int i, ret; 432 463 433 464 if (matcher->flags & MLX5HWS_MATCHER_FLAGS_COLLISION) 434 465 return 0; 435 466 467 + max_stes = 0; 436 468 for (i = 0; i < matcher->num_of_at; i++) { 437 469 struct mlx5hws_action_template *at = &matcher->at[i]; 438 470 ··· 380 548 /* Future: Optimize reparse */ 381 549 } 382 550 383 - /* There are no additional STEs required for matcher */ 384 - if (!max_stes) 385 - return 0; 386 - 387 - matcher->action_ste.max_stes = max_stes; 388 - 389 - action_ste = &matcher->action_ste; 390 - 391 - /* Allocate action STE mempool */ 392 - pool_attr.table_type = tbl->type; 393 - pool_attr.pool_type = MLX5HWS_POOL_TYPE_STE; 394 - pool_attr.flags = MLX5HWS_POOL_FLAGS_FOR_STE_ACTION_POOL; 395 - /* Pool size is similar to action RTC size */ 396 - pool_attr.alloc_log_sz = ilog2(roundup_pow_of_two(action_ste->max_stes)) + 397 - matcher->attr.table.sz_row_log + 398 - MLX5HWS_MATCHER_ACTION_RTC_UPDATE_MULT; 399 - hws_matcher_set_pool_attr(&pool_attr, matcher); 400 - action_ste->pool = mlx5hws_pool_create(ctx, &pool_attr); 401 - if (!action_ste->pool) { 402 - mlx5hws_err(ctx, "Failed to create action ste pool\n"); 403 - return -EINVAL; 404 - } 405 - 406 - /* Allocate action RTC */ 407 - ret = hws_matcher_create_rtc(matcher, HWS_MATCHER_RTC_TYPE_STE_ARRAY); 408 - if (ret) { 409 - mlx5hws_err(ctx, "Failed to create action RTC\n"); 410 - goto free_ste_pool; 411 - } 412 - 413 - /* Allocate STC for jumps to STE */ 414 - stc_attr.action_offset = MLX5HWS_ACTION_OFFSET_HIT; 415 - stc_attr.action_type = MLX5_IFC_STC_ACTION_TYPE_JUMP_TO_STE_TABLE; 416 - stc_attr.reparse_mode = MLX5_IFC_STC_REPARSE_IGNORE; 417 - stc_attr.ste_table.ste = action_ste->ste; 418 - stc_attr.ste_table.ste_pool = action_ste->pool; 419 - stc_attr.ste_table.match_definer_id = ctx->caps->trivial_match_definer; 420 - 421 - ret = mlx5hws_action_alloc_single_stc(ctx, &stc_attr, tbl->type, 422 - &action_ste->stc); 423 - if (ret) { 424 - mlx5hws_err(ctx, "Failed to create action jump to table STC\n"); 425 - goto free_rtc; 426 - } 551 + matcher->num_of_action_stes = max_stes; 427 552 428 553 return 0; 429 - 430 - free_rtc: 431 - hws_matcher_destroy_rtc(matcher, HWS_MATCHER_RTC_TYPE_STE_ARRAY); 432 - free_ste_pool: 433 - mlx5hws_pool_destroy(action_ste->pool); 434 - return ret; 435 - } 436 - 437 - static void hws_matcher_unbind_at(struct mlx5hws_matcher *matcher) 438 - { 439 - struct mlx5hws_matcher_action_ste *action_ste; 440 - struct mlx5hws_table *tbl = matcher->tbl; 441 - 442 - action_ste = &matcher->action_ste; 443 - 444 - if (!action_ste->max_stes || 445 - matcher->flags & MLX5HWS_MATCHER_FLAGS_COLLISION || 446 - mlx5hws_matcher_is_in_resize(matcher)) 447 - return; 448 - 449 - mlx5hws_action_free_single_stc(tbl->ctx, tbl->type, &action_ste->stc); 450 - hws_matcher_destroy_rtc(matcher, HWS_MATCHER_RTC_TYPE_STE_ARRAY); 451 - mlx5hws_pool_destroy(action_ste->pool); 452 554 } 453 555 454 556 static int hws_matcher_bind_mt(struct mlx5hws_matcher *matcher) ··· 404 638 /* Create an STE pool per matcher*/ 405 639 pool_attr.table_type = matcher->tbl->type; 406 640 pool_attr.pool_type = MLX5HWS_POOL_TYPE_STE; 407 - pool_attr.flags = MLX5HWS_POOL_FLAGS_FOR_MATCHER_STE_POOL; 408 641 pool_attr.alloc_log_sz = matcher->attr.table.sz_col_log + 409 642 matcher->attr.table.sz_row_log; 410 643 hws_matcher_set_pool_attr(&pool_attr, matcher); ··· 526 761 /* Create matcher end flow table anchor */ 527 762 ret = hws_matcher_create_end_ft(matcher); 528 763 if (ret) 529 - goto unbind_at; 764 + goto unbind_mt; 530 765 531 766 /* Allocate the RTC for the new matcher */ 532 - ret = hws_matcher_create_rtc(matcher, HWS_MATCHER_RTC_TYPE_MATCH); 767 + ret = hws_matcher_create_rtc(matcher); 533 768 if (ret) 534 769 goto destroy_end_ft; 535 770 ··· 541 776 return 0; 542 777 543 778 destroy_rtc: 544 - hws_matcher_destroy_rtc(matcher, HWS_MATCHER_RTC_TYPE_MATCH); 779 + hws_matcher_destroy_rtc(matcher); 545 780 destroy_end_ft: 546 781 hws_matcher_destroy_end_ft(matcher); 547 - unbind_at: 548 - hws_matcher_unbind_at(matcher); 549 782 unbind_mt: 550 783 hws_matcher_unbind_mt(matcher); 551 784 return ret; ··· 551 788 552 789 static void hws_matcher_destroy_and_disconnect(struct mlx5hws_matcher *matcher) 553 790 { 554 - hws_matcher_resize_uninit(matcher); 555 791 hws_matcher_disconnect(matcher); 556 - hws_matcher_destroy_rtc(matcher, HWS_MATCHER_RTC_TYPE_MATCH); 792 + hws_matcher_destroy_rtc(matcher); 557 793 hws_matcher_destroy_end_ft(matcher); 558 - hws_matcher_unbind_at(matcher); 559 794 hws_matcher_unbind_mt(matcher); 560 795 } 561 796 ··· 574 813 col_matcher = kzalloc(sizeof(*matcher), GFP_KERNEL); 575 814 if (!col_matcher) 576 815 return -ENOMEM; 577 - 578 - INIT_LIST_HEAD(&col_matcher->resize_data); 579 816 580 817 col_matcher->tbl = matcher->tbl; 581 818 col_matcher->mt = matcher->mt; ··· 628 869 struct mlx5hws_context *ctx = matcher->tbl->ctx; 629 870 int ret; 630 871 631 - INIT_LIST_HEAD(&matcher->resize_data); 632 - 633 872 mutex_lock(&ctx->ctrl_lock); 634 873 635 874 /* Allocate matcher resource and connect to the packet pipe */ ··· 662 905 return 0; 663 906 } 664 907 908 + static int hws_matcher_grow_at_array(struct mlx5hws_matcher *matcher) 909 + { 910 + void *p; 911 + 912 + if (matcher->size_of_at_array >= MLX5HWS_MATCHER_MAX_AT) 913 + return -ENOMEM; 914 + 915 + matcher->size_of_at_array *= 2; 916 + p = krealloc(matcher->at, 917 + matcher->size_of_at_array * sizeof(*matcher->at), 918 + __GFP_ZERO | GFP_KERNEL); 919 + if (!p) { 920 + matcher->size_of_at_array /= 2; 921 + return -ENOMEM; 922 + } 923 + 924 + matcher->at = p; 925 + 926 + return 0; 927 + } 928 + 665 929 int mlx5hws_matcher_attach_at(struct mlx5hws_matcher *matcher, 666 930 struct mlx5hws_action_template *at) 667 931 { 668 932 bool is_jumbo = mlx5hws_matcher_mt_is_jumbo(matcher->mt); 669 - struct mlx5hws_context *ctx = matcher->tbl->ctx; 670 933 u32 required_stes; 671 934 int ret; 672 935 673 - if (!matcher->attr.max_num_of_at_attach) { 674 - mlx5hws_dbg(ctx, "Num of current at (%d) exceed allowed value\n", 675 - matcher->num_of_at); 676 - return -EOPNOTSUPP; 936 + if (unlikely(matcher->num_of_at >= matcher->size_of_at_array)) { 937 + ret = hws_matcher_grow_at_array(matcher); 938 + if (ret) 939 + return ret; 940 + 941 + if (matcher->col_matcher) { 942 + ret = hws_matcher_grow_at_array(matcher->col_matcher); 943 + if (ret) 944 + return ret; 945 + } 677 946 } 678 947 679 948 ret = hws_matcher_check_and_process_at(matcher, at); ··· 707 924 return ret; 708 925 709 926 required_stes = at->num_of_action_stes - (!is_jumbo || at->only_term); 710 - if (matcher->action_ste.max_stes < required_stes) { 711 - mlx5hws_dbg(ctx, "Required STEs [%d] exceeds initial action template STE [%d]\n", 712 - required_stes, matcher->action_ste.max_stes); 713 - return -ENOMEM; 714 - } 927 + if (matcher->num_of_action_stes < required_stes) 928 + matcher->num_of_action_stes = required_stes; 715 929 716 930 matcher->at[matcher->num_of_at] = *at; 717 931 matcher->num_of_at += 1; 718 - matcher->attr.max_num_of_at_attach -= 1; 719 932 720 933 if (matcher->col_matcher) 721 934 matcher->col_matcher->num_of_at = matcher->num_of_at; ··· 739 960 if (!matcher->mt) 740 961 return -ENOMEM; 741 962 742 - matcher->at = kvcalloc(num_of_at + matcher->attr.max_num_of_at_attach, 743 - sizeof(*matcher->at), 963 + matcher->size_of_at_array = 964 + num_of_at + matcher->attr.max_num_of_at_attach; 965 + matcher->at = kvcalloc(matcher->size_of_at_array, sizeof(*matcher->at), 744 966 GFP_KERNEL); 745 967 if (!matcher->at) { 746 968 mlx5hws_err(ctx, "Failed to allocate action template array\n"); ··· 890 1110 return -EINVAL; 891 1111 } 892 1112 893 - if (src_matcher->action_ste.max_stes > dst_matcher->action_ste.max_stes) { 1113 + if (src_matcher->num_of_action_stes > dst_matcher->num_of_action_stes) { 894 1114 mlx5hws_err(ctx, "Src/dst matcher max STEs mismatch\n"); 895 1115 return -EINVAL; 896 1116 } ··· 918 1138 goto out; 919 1139 920 1140 src_matcher->resize_dst = dst_matcher; 921 - 922 - ret = hws_matcher_resize_init(src_matcher); 923 - if (ret) 924 - src_matcher->resize_dst = NULL; 925 1141 926 1142 out: 927 1143 mutex_unlock(&src_matcher->tbl->ctx->ctrl_lock);
+5 -21
drivers/net/ethernet/mellanox/mlx5/core/steering/hws/matcher.h
··· 23 23 */ 24 24 #define MLX5HWS_MATCHER_ACTION_RTC_UPDATE_MULT 1 25 25 26 + /* Maximum number of action templates that can be attached to a matcher. */ 27 + #define MLX5HWS_MATCHER_MAX_AT 128 28 + 26 29 enum mlx5hws_matcher_offset { 27 30 MLX5HWS_MATCHER_OFFSET_TAG_DW1 = 12, 28 31 MLX5HWS_MATCHER_OFFSET_TAG_DW0 = 13, ··· 45 42 }; 46 43 47 44 struct mlx5hws_matcher_match_ste { 48 - struct mlx5hws_pool_chunk ste; 49 45 u32 rtc_0_id; 50 46 u32 rtc_1_id; 51 47 struct mlx5hws_pool *pool; 52 - }; 53 - 54 - struct mlx5hws_matcher_action_ste { 55 - struct mlx5hws_pool_chunk ste; 56 - struct mlx5hws_pool_chunk stc; 57 - u32 rtc_0_id; 58 - u32 rtc_1_id; 59 - struct mlx5hws_pool *pool; 60 - u8 max_stes; 61 - }; 62 - 63 - struct mlx5hws_matcher_resize_data { 64 - struct mlx5hws_pool_chunk stc; 65 - u32 rtc_0_id; 66 - u32 rtc_1_id; 67 - struct mlx5hws_pool *pool; 68 - u8 max_stes; 69 - struct list_head list_node; 70 48 }; 71 49 72 50 struct mlx5hws_matcher { ··· 56 72 struct mlx5hws_match_template *mt; 57 73 struct mlx5hws_action_template *at; 58 74 u8 num_of_at; 75 + u8 size_of_at_array; 59 76 u8 num_of_mt; 77 + u8 num_of_action_stes; 60 78 /* enum mlx5hws_matcher_flags */ 61 79 u8 flags; 62 80 u32 end_ft_id; 63 81 struct mlx5hws_matcher *col_matcher; 64 82 struct mlx5hws_matcher *resize_dst; 65 83 struct mlx5hws_matcher_match_ste match_ste; 66 - struct mlx5hws_matcher_action_ste action_ste; 67 84 struct list_head list_node; 68 - struct list_head resize_data; 69 85 }; 70 86 71 87 static inline bool
+136 -383
drivers/net/ethernet/mellanox/mlx5/core/steering/hws/pool.c
··· 20 20 kfree(resource); 21 21 } 22 22 23 - static void hws_pool_resource_free(struct mlx5hws_pool *pool, 24 - int resource_idx) 23 + static void hws_pool_resource_free(struct mlx5hws_pool *pool) 25 24 { 26 - hws_pool_free_one_resource(pool->resource[resource_idx]); 27 - pool->resource[resource_idx] = NULL; 25 + hws_pool_free_one_resource(pool->resource); 26 + pool->resource = NULL; 28 27 29 28 if (pool->tbl_type == MLX5HWS_TABLE_TYPE_FDB) { 30 - hws_pool_free_one_resource(pool->mirror_resource[resource_idx]); 31 - pool->mirror_resource[resource_idx] = NULL; 29 + hws_pool_free_one_resource(pool->mirror_resource); 30 + pool->mirror_resource = NULL; 32 31 } 33 32 } 34 33 ··· 60 61 ret = -EINVAL; 61 62 } 62 63 63 - if (ret) { 64 - mlx5hws_err(pool->ctx, "Failed to allocate resource objects\n"); 64 + if (ret) 65 65 goto free_resource; 66 - } 67 66 68 67 resource->pool = pool; 69 68 resource->range = 1 << log_range; ··· 74 77 return NULL; 75 78 } 76 79 77 - static int 78 - hws_pool_resource_alloc(struct mlx5hws_pool *pool, u32 log_range, int idx) 80 + static int hws_pool_resource_alloc(struct mlx5hws_pool *pool) 79 81 { 80 82 struct mlx5hws_pool_resource *resource; 81 83 u32 fw_ft_type, opt_log_range; 82 84 83 85 fw_ft_type = mlx5hws_table_get_res_fw_ft_type(pool->tbl_type, false); 84 - opt_log_range = pool->opt_type == MLX5HWS_POOL_OPTIMIZE_ORIG ? 0 : log_range; 86 + opt_log_range = pool->opt_type == MLX5HWS_POOL_OPTIMIZE_MIRROR ? 87 + 0 : pool->alloc_log_sz; 85 88 resource = hws_pool_create_one_resource(pool, opt_log_range, fw_ft_type); 86 89 if (!resource) { 87 - mlx5hws_err(pool->ctx, "Failed allocating resource\n"); 90 + mlx5hws_err(pool->ctx, "Failed to allocate resource\n"); 88 91 return -EINVAL; 89 92 } 90 93 91 - pool->resource[idx] = resource; 94 + pool->resource = resource; 92 95 93 96 if (pool->tbl_type == MLX5HWS_TABLE_TYPE_FDB) { 94 97 struct mlx5hws_pool_resource *mirror_resource; 95 98 96 99 fw_ft_type = mlx5hws_table_get_res_fw_ft_type(pool->tbl_type, true); 97 - opt_log_range = pool->opt_type == MLX5HWS_POOL_OPTIMIZE_MIRROR ? 0 : log_range; 100 + opt_log_range = pool->opt_type == MLX5HWS_POOL_OPTIMIZE_ORIG ? 101 + 0 : pool->alloc_log_sz; 98 102 mirror_resource = hws_pool_create_one_resource(pool, opt_log_range, fw_ft_type); 99 103 if (!mirror_resource) { 100 - mlx5hws_err(pool->ctx, "Failed allocating mirrored resource\n"); 104 + mlx5hws_err(pool->ctx, "Failed to allocate mirrored resource\n"); 101 105 hws_pool_free_one_resource(resource); 102 - pool->resource[idx] = NULL; 106 + pool->resource = NULL; 103 107 return -EINVAL; 104 108 } 105 - pool->mirror_resource[idx] = mirror_resource; 109 + pool->mirror_resource = mirror_resource; 106 110 } 107 111 108 112 return 0; 109 113 } 110 114 111 - static unsigned long *hws_pool_create_and_init_bitmap(u32 log_range) 115 + static int hws_pool_buddy_init(struct mlx5hws_pool *pool) 112 116 { 113 - unsigned long *cur_bmp; 117 + struct mlx5hws_buddy_mem *buddy; 114 118 115 - cur_bmp = bitmap_zalloc(1 << log_range, GFP_KERNEL); 116 - if (!cur_bmp) 117 - return NULL; 119 + buddy = mlx5hws_buddy_create(pool->alloc_log_sz); 120 + if (!buddy) { 121 + mlx5hws_err(pool->ctx, "Failed to create buddy order: %zu\n", 122 + pool->alloc_log_sz); 123 + return -ENOMEM; 124 + } 118 125 119 - bitmap_fill(cur_bmp, 1 << log_range); 126 + if (hws_pool_resource_alloc(pool) != 0) { 127 + mlx5hws_err(pool->ctx, "Failed to create resource type: %d size %zu\n", 128 + pool->type, pool->alloc_log_sz); 129 + mlx5hws_buddy_cleanup(buddy); 130 + return -ENOMEM; 131 + } 120 132 121 - return cur_bmp; 133 + pool->db.buddy = buddy; 134 + 135 + return 0; 136 + } 137 + 138 + static int hws_pool_buddy_db_get_chunk(struct mlx5hws_pool *pool, 139 + struct mlx5hws_pool_chunk *chunk) 140 + { 141 + struct mlx5hws_buddy_mem *buddy = pool->db.buddy; 142 + 143 + if (!buddy) { 144 + mlx5hws_err(pool->ctx, "Bad buddy state\n"); 145 + return -EINVAL; 146 + } 147 + 148 + chunk->offset = mlx5hws_buddy_alloc_mem(buddy, chunk->order); 149 + if (chunk->offset >= 0) 150 + return 0; 151 + 152 + return -ENOMEM; 122 153 } 123 154 124 155 static void hws_pool_buddy_db_put_chunk(struct mlx5hws_pool *pool, ··· 154 129 { 155 130 struct mlx5hws_buddy_mem *buddy; 156 131 157 - buddy = pool->db.buddy_manager->buddies[chunk->resource_idx]; 132 + buddy = pool->db.buddy; 158 133 if (!buddy) { 159 - mlx5hws_err(pool->ctx, "No such buddy (%d)\n", chunk->resource_idx); 134 + mlx5hws_err(pool->ctx, "Bad buddy state\n"); 160 135 return; 161 136 } 162 137 163 138 mlx5hws_buddy_free_mem(buddy, chunk->offset, chunk->order); 164 139 } 165 140 166 - static struct mlx5hws_buddy_mem * 167 - hws_pool_buddy_get_next_buddy(struct mlx5hws_pool *pool, int idx, 168 - u32 order, bool *is_new_buddy) 169 - { 170 - static struct mlx5hws_buddy_mem *buddy; 171 - u32 new_buddy_size; 172 - 173 - buddy = pool->db.buddy_manager->buddies[idx]; 174 - if (buddy) 175 - return buddy; 176 - 177 - new_buddy_size = max(pool->alloc_log_sz, order); 178 - *is_new_buddy = true; 179 - buddy = mlx5hws_buddy_create(new_buddy_size); 180 - if (!buddy) { 181 - mlx5hws_err(pool->ctx, "Failed to create buddy order: %d index: %d\n", 182 - new_buddy_size, idx); 183 - return NULL; 184 - } 185 - 186 - if (hws_pool_resource_alloc(pool, new_buddy_size, idx) != 0) { 187 - mlx5hws_err(pool->ctx, "Failed to create resource type: %d: size %d index: %d\n", 188 - pool->type, new_buddy_size, idx); 189 - mlx5hws_buddy_cleanup(buddy); 190 - return NULL; 191 - } 192 - 193 - pool->db.buddy_manager->buddies[idx] = buddy; 194 - 195 - return buddy; 196 - } 197 - 198 - static int hws_pool_buddy_get_mem_chunk(struct mlx5hws_pool *pool, 199 - int order, 200 - u32 *buddy_idx, 201 - int *seg) 202 - { 203 - struct mlx5hws_buddy_mem *buddy; 204 - bool new_mem = false; 205 - int ret = 0; 206 - int i; 207 - 208 - *seg = -1; 209 - 210 - /* Find the next free place from the buddy array */ 211 - while (*seg < 0) { 212 - for (i = 0; i < MLX5HWS_POOL_RESOURCE_ARR_SZ; i++) { 213 - buddy = hws_pool_buddy_get_next_buddy(pool, i, 214 - order, 215 - &new_mem); 216 - if (!buddy) { 217 - ret = -ENOMEM; 218 - goto out; 219 - } 220 - 221 - *seg = mlx5hws_buddy_alloc_mem(buddy, order); 222 - if (*seg >= 0) 223 - goto found; 224 - 225 - if (pool->flags & MLX5HWS_POOL_FLAGS_ONE_RESOURCE) { 226 - mlx5hws_err(pool->ctx, 227 - "Fail to allocate seg for one resource pool\n"); 228 - ret = -ENOMEM; 229 - goto out; 230 - } 231 - 232 - if (new_mem) { 233 - /* We have new memory pool, should be place for us */ 234 - mlx5hws_err(pool->ctx, 235 - "No memory for order: %d with buddy no: %d\n", 236 - order, i); 237 - ret = -ENOMEM; 238 - goto out; 239 - } 240 - } 241 - } 242 - 243 - found: 244 - *buddy_idx = i; 245 - out: 246 - return ret; 247 - } 248 - 249 - static int hws_pool_buddy_db_get_chunk(struct mlx5hws_pool *pool, 250 - struct mlx5hws_pool_chunk *chunk) 251 - { 252 - int ret = 0; 253 - 254 - /* Go over the buddies and find next free slot */ 255 - ret = hws_pool_buddy_get_mem_chunk(pool, chunk->order, 256 - &chunk->resource_idx, 257 - &chunk->offset); 258 - if (ret) 259 - mlx5hws_err(pool->ctx, "Failed to get free slot for chunk with order: %d\n", 260 - chunk->order); 261 - 262 - return ret; 263 - } 264 - 265 141 static void hws_pool_buddy_db_uninit(struct mlx5hws_pool *pool) 266 142 { 267 143 struct mlx5hws_buddy_mem *buddy; 268 - int i; 269 144 270 - for (i = 0; i < MLX5HWS_POOL_RESOURCE_ARR_SZ; i++) { 271 - buddy = pool->db.buddy_manager->buddies[i]; 272 - if (buddy) { 273 - mlx5hws_buddy_cleanup(buddy); 274 - kfree(buddy); 275 - pool->db.buddy_manager->buddies[i] = NULL; 276 - } 145 + buddy = pool->db.buddy; 146 + if (buddy) { 147 + mlx5hws_buddy_cleanup(buddy); 148 + kfree(buddy); 149 + pool->db.buddy = NULL; 277 150 } 278 - 279 - kfree(pool->db.buddy_manager); 280 151 } 281 152 282 - static int hws_pool_buddy_db_init(struct mlx5hws_pool *pool, u32 log_range) 153 + static int hws_pool_buddy_db_init(struct mlx5hws_pool *pool) 283 154 { 284 - pool->db.buddy_manager = kzalloc(sizeof(*pool->db.buddy_manager), GFP_KERNEL); 285 - if (!pool->db.buddy_manager) 286 - return -ENOMEM; 155 + int ret; 287 156 288 - if (pool->flags & MLX5HWS_POOL_FLAGS_ALLOC_MEM_ON_CREATE) { 289 - bool new_buddy; 290 - 291 - if (!hws_pool_buddy_get_next_buddy(pool, 0, log_range, &new_buddy)) { 292 - mlx5hws_err(pool->ctx, 293 - "Failed allocating memory on create log_sz: %d\n", log_range); 294 - kfree(pool->db.buddy_manager); 295 - return -ENOMEM; 296 - } 297 - } 157 + ret = hws_pool_buddy_init(pool); 158 + if (ret) 159 + return ret; 298 160 299 161 pool->p_db_uninit = &hws_pool_buddy_db_uninit; 300 162 pool->p_get_chunk = &hws_pool_buddy_db_get_chunk; ··· 190 278 return 0; 191 279 } 192 280 193 - static int hws_pool_create_resource_on_index(struct mlx5hws_pool *pool, 194 - u32 alloc_size, int idx) 281 + static unsigned long *hws_pool_create_and_init_bitmap(u32 log_range) 195 282 { 196 - int ret = hws_pool_resource_alloc(pool, alloc_size, idx); 283 + unsigned long *bitmap; 197 284 198 - if (ret) { 199 - mlx5hws_err(pool->ctx, "Failed to create resource type: %d: size %d index: %d\n", 200 - pool->type, alloc_size, idx); 201 - return ret; 202 - } 203 - 204 - return 0; 205 - } 206 - 207 - static struct mlx5hws_pool_elements * 208 - hws_pool_element_create_new_elem(struct mlx5hws_pool *pool, u32 order, int idx) 209 - { 210 - struct mlx5hws_pool_elements *elem; 211 - u32 alloc_size; 212 - 213 - alloc_size = pool->alloc_log_sz; 214 - 215 - elem = kzalloc(sizeof(*elem), GFP_KERNEL); 216 - if (!elem) 285 + bitmap = bitmap_zalloc(1 << log_range, GFP_KERNEL); 286 + if (!bitmap) 217 287 return NULL; 218 288 219 - /* Sharing the same resource, also means that all the elements are with size 1 */ 220 - if ((pool->flags & MLX5HWS_POOL_FLAGS_FIXED_SIZE_OBJECTS) && 221 - !(pool->flags & MLX5HWS_POOL_FLAGS_RESOURCE_PER_CHUNK)) { 222 - /* Currently all chunks in size 1 */ 223 - elem->bitmap = hws_pool_create_and_init_bitmap(alloc_size - order); 224 - if (!elem->bitmap) { 225 - mlx5hws_err(pool->ctx, 226 - "Failed to create bitmap type: %d: size %d index: %d\n", 227 - pool->type, alloc_size, idx); 228 - goto free_elem; 229 - } 289 + bitmap_fill(bitmap, 1 << log_range); 230 290 231 - elem->log_size = alloc_size - order; 232 - } 233 - 234 - if (hws_pool_create_resource_on_index(pool, alloc_size, idx)) { 235 - mlx5hws_err(pool->ctx, "Failed to create resource type: %d: size %d index: %d\n", 236 - pool->type, alloc_size, idx); 237 - goto free_db; 238 - } 239 - 240 - pool->db.element_manager->elements[idx] = elem; 241 - 242 - return elem; 243 - 244 - free_db: 245 - bitmap_free(elem->bitmap); 246 - free_elem: 247 - kfree(elem); 248 - return NULL; 291 + return bitmap; 249 292 } 250 293 251 - static int hws_pool_element_find_seg(struct mlx5hws_pool_elements *elem, int *seg) 294 + static int hws_pool_bitmap_init(struct mlx5hws_pool *pool) 252 295 { 253 - unsigned int segment, size; 296 + unsigned long *bitmap; 254 297 255 - size = 1 << elem->log_size; 256 - 257 - segment = find_first_bit(elem->bitmap, size); 258 - if (segment >= size) { 259 - elem->is_full = true; 298 + bitmap = hws_pool_create_and_init_bitmap(pool->alloc_log_sz); 299 + if (!bitmap) { 300 + mlx5hws_err(pool->ctx, "Failed to create bitmap order: %zu\n", 301 + pool->alloc_log_sz); 260 302 return -ENOMEM; 261 303 } 262 304 263 - bitmap_clear(elem->bitmap, segment, 1); 264 - *seg = segment; 265 - return 0; 266 - } 267 - 268 - static int 269 - hws_pool_onesize_element_get_mem_chunk(struct mlx5hws_pool *pool, u32 order, 270 - u32 *idx, int *seg) 271 - { 272 - struct mlx5hws_pool_elements *elem; 273 - 274 - elem = pool->db.element_manager->elements[0]; 275 - if (!elem) 276 - elem = hws_pool_element_create_new_elem(pool, order, 0); 277 - if (!elem) 278 - goto err_no_elem; 279 - 280 - if (hws_pool_element_find_seg(elem, seg) != 0) { 281 - mlx5hws_err(pool->ctx, "No more resources (last request order: %d)\n", order); 305 + if (hws_pool_resource_alloc(pool) != 0) { 306 + mlx5hws_err(pool->ctx, "Failed to create resource type: %d: size %zu\n", 307 + pool->type, pool->alloc_log_sz); 308 + bitmap_free(bitmap); 282 309 return -ENOMEM; 283 310 } 284 311 285 - *idx = 0; 286 - elem->num_of_elements++; 287 - return 0; 312 + pool->db.bitmap = bitmap; 288 313 289 - err_no_elem: 290 - mlx5hws_err(pool->ctx, "Failed to allocate element for order: %d\n", order); 291 - return -ENOMEM; 314 + return 0; 292 315 } 293 316 294 - static int 295 - hws_pool_general_element_get_mem_chunk(struct mlx5hws_pool *pool, u32 order, 296 - u32 *idx, int *seg) 317 + static int hws_pool_bitmap_db_get_chunk(struct mlx5hws_pool *pool, 318 + struct mlx5hws_pool_chunk *chunk) 297 319 { 298 - int ret, i; 320 + unsigned long *bitmap, size; 299 321 300 - for (i = 0; i < MLX5HWS_POOL_RESOURCE_ARR_SZ; i++) { 301 - if (!pool->resource[i]) { 302 - ret = hws_pool_create_resource_on_index(pool, order, i); 303 - if (ret) 304 - goto err_no_res; 305 - *idx = i; 306 - *seg = 0; /* One memory slot in that element */ 307 - return 0; 308 - } 322 + if (chunk->order != 0) { 323 + mlx5hws_err(pool->ctx, "Pool only supports order 0 allocs\n"); 324 + return -EINVAL; 309 325 } 310 326 311 - mlx5hws_err(pool->ctx, "No more resources (last request order: %d)\n", order); 312 - return -ENOMEM; 327 + bitmap = pool->db.bitmap; 328 + if (!bitmap) { 329 + mlx5hws_err(pool->ctx, "Bad bitmap state\n"); 330 + return -EINVAL; 331 + } 313 332 314 - err_no_res: 315 - mlx5hws_err(pool->ctx, "Failed to allocate element for order: %d\n", order); 316 - return -ENOMEM; 317 - } 333 + size = 1 << pool->alloc_log_sz; 318 334 319 - static int hws_pool_general_element_db_get_chunk(struct mlx5hws_pool *pool, 320 - struct mlx5hws_pool_chunk *chunk) 321 - { 322 - int ret; 335 + chunk->offset = find_first_bit(bitmap, size); 336 + if (chunk->offset >= size) 337 + return -ENOMEM; 323 338 324 - /* Go over all memory elements and find/allocate free slot */ 325 - ret = hws_pool_general_element_get_mem_chunk(pool, chunk->order, 326 - &chunk->resource_idx, 327 - &chunk->offset); 328 - if (ret) 329 - mlx5hws_err(pool->ctx, "Failed to get free slot for chunk with order: %d\n", 330 - chunk->order); 331 - 332 - return ret; 333 - } 334 - 335 - static void hws_pool_general_element_db_put_chunk(struct mlx5hws_pool *pool, 336 - struct mlx5hws_pool_chunk *chunk) 337 - { 338 - if (unlikely(!pool->resource[chunk->resource_idx])) 339 - pr_warn("HWS: invalid resource with index %d\n", chunk->resource_idx); 340 - 341 - if (pool->flags & MLX5HWS_POOL_FLAGS_RELEASE_FREE_RESOURCE) 342 - hws_pool_resource_free(pool, chunk->resource_idx); 343 - } 344 - 345 - static void hws_pool_general_element_db_uninit(struct mlx5hws_pool *pool) 346 - { 347 - (void)pool; 348 - } 349 - 350 - /* This memory management works as the following: 351 - * - At start doesn't allocate no mem at all. 352 - * - When new request for chunk arrived: 353 - * allocate resource and give it. 354 - * - When free that chunk: 355 - * the resource is freed. 356 - */ 357 - static int hws_pool_general_element_db_init(struct mlx5hws_pool *pool) 358 - { 359 - pool->p_db_uninit = &hws_pool_general_element_db_uninit; 360 - pool->p_get_chunk = &hws_pool_general_element_db_get_chunk; 361 - pool->p_put_chunk = &hws_pool_general_element_db_put_chunk; 339 + bitmap_clear(bitmap, chunk->offset, 1); 362 340 363 341 return 0; 364 342 } 365 343 366 - static void hws_onesize_element_db_destroy_element(struct mlx5hws_pool *pool, 367 - struct mlx5hws_pool_elements *elem, 368 - struct mlx5hws_pool_chunk *chunk) 344 + static void hws_pool_bitmap_db_put_chunk(struct mlx5hws_pool *pool, 345 + struct mlx5hws_pool_chunk *chunk) 369 346 { 370 - if (unlikely(!pool->resource[chunk->resource_idx])) 371 - pr_warn("HWS: invalid resource with index %d\n", chunk->resource_idx); 347 + unsigned long *bitmap; 372 348 373 - hws_pool_resource_free(pool, chunk->resource_idx); 374 - kfree(elem); 375 - pool->db.element_manager->elements[chunk->resource_idx] = NULL; 376 - } 377 - 378 - static void hws_onesize_element_db_put_chunk(struct mlx5hws_pool *pool, 379 - struct mlx5hws_pool_chunk *chunk) 380 - { 381 - struct mlx5hws_pool_elements *elem; 382 - 383 - if (unlikely(chunk->resource_idx)) 384 - pr_warn("HWS: invalid resource with index %d\n", chunk->resource_idx); 385 - 386 - elem = pool->db.element_manager->elements[chunk->resource_idx]; 387 - if (!elem) { 388 - mlx5hws_err(pool->ctx, "No such element (%d)\n", chunk->resource_idx); 349 + bitmap = pool->db.bitmap; 350 + if (!bitmap) { 351 + mlx5hws_err(pool->ctx, "Bad bitmap state\n"); 389 352 return; 390 353 } 391 354 392 - bitmap_set(elem->bitmap, chunk->offset, 1); 393 - elem->is_full = false; 394 - elem->num_of_elements--; 395 - 396 - if (pool->flags & MLX5HWS_POOL_FLAGS_RELEASE_FREE_RESOURCE && 397 - !elem->num_of_elements) 398 - hws_onesize_element_db_destroy_element(pool, elem, chunk); 355 + bitmap_set(bitmap, chunk->offset, 1); 399 356 } 400 357 401 - static int hws_onesize_element_db_get_chunk(struct mlx5hws_pool *pool, 402 - struct mlx5hws_pool_chunk *chunk) 358 + static void hws_pool_bitmap_db_uninit(struct mlx5hws_pool *pool) 403 359 { 404 - int ret = 0; 360 + unsigned long *bitmap; 405 361 406 - /* Go over all memory elements and find/allocate free slot */ 407 - ret = hws_pool_onesize_element_get_mem_chunk(pool, chunk->order, 408 - &chunk->resource_idx, 409 - &chunk->offset); 410 - if (ret) 411 - mlx5hws_err(pool->ctx, "Failed to get free slot for chunk with order: %d\n", 412 - chunk->order); 413 - 414 - return ret; 415 - } 416 - 417 - static void hws_onesize_element_db_uninit(struct mlx5hws_pool *pool) 418 - { 419 - struct mlx5hws_pool_elements *elem; 420 - int i; 421 - 422 - for (i = 0; i < MLX5HWS_POOL_RESOURCE_ARR_SZ; i++) { 423 - elem = pool->db.element_manager->elements[i]; 424 - if (elem) { 425 - bitmap_free(elem->bitmap); 426 - kfree(elem); 427 - pool->db.element_manager->elements[i] = NULL; 428 - } 362 + bitmap = pool->db.bitmap; 363 + if (bitmap) { 364 + bitmap_free(bitmap); 365 + pool->db.bitmap = NULL; 429 366 } 430 - kfree(pool->db.element_manager); 431 367 } 432 368 433 - /* This memory management works as the following: 434 - * - At start doesn't allocate no mem at all. 435 - * - When new request for chunk arrived: 436 - * aloocate the first and only slot of memory/resource 437 - * when it ended return error. 438 - */ 439 - static int hws_pool_onesize_element_db_init(struct mlx5hws_pool *pool) 369 + static int hws_pool_bitmap_db_init(struct mlx5hws_pool *pool) 440 370 { 441 - pool->db.element_manager = kzalloc(sizeof(*pool->db.element_manager), GFP_KERNEL); 442 - if (!pool->db.element_manager) 443 - return -ENOMEM; 371 + int ret; 444 372 445 - pool->p_db_uninit = &hws_onesize_element_db_uninit; 446 - pool->p_get_chunk = &hws_onesize_element_db_get_chunk; 447 - pool->p_put_chunk = &hws_onesize_element_db_put_chunk; 373 + ret = hws_pool_bitmap_init(pool); 374 + if (ret) 375 + return ret; 376 + 377 + pool->p_db_uninit = &hws_pool_bitmap_db_uninit; 378 + pool->p_get_chunk = &hws_pool_bitmap_db_get_chunk; 379 + pool->p_put_chunk = &hws_pool_bitmap_db_put_chunk; 448 380 449 381 return 0; 450 382 } ··· 298 542 { 299 543 int ret; 300 544 301 - if (db_type == MLX5HWS_POOL_DB_TYPE_GENERAL_SIZE) 302 - ret = hws_pool_general_element_db_init(pool); 303 - else if (db_type == MLX5HWS_POOL_DB_TYPE_ONE_SIZE_RESOURCE) 304 - ret = hws_pool_onesize_element_db_init(pool); 545 + if (db_type == MLX5HWS_POOL_DB_TYPE_BITMAP) 546 + ret = hws_pool_bitmap_db_init(pool); 305 547 else 306 - ret = hws_pool_buddy_db_init(pool, pool->alloc_log_sz); 548 + ret = hws_pool_buddy_db_init(pool); 307 549 308 550 if (ret) { 309 - mlx5hws_err(pool->ctx, "Failed to init general db : %d (ret: %d)\n", db_type, ret); 551 + mlx5hws_err(pool->ctx, "Failed to init pool type: %d (ret: %d)\n", 552 + db_type, ret); 310 553 return ret; 311 554 } 312 555 ··· 324 569 325 570 mutex_lock(&pool->lock); 326 571 ret = pool->p_get_chunk(pool, chunk); 572 + if (ret == 0) 573 + pool->available_elems -= 1 << chunk->order; 327 574 mutex_unlock(&pool->lock); 328 575 329 576 return ret; ··· 336 579 { 337 580 mutex_lock(&pool->lock); 338 581 pool->p_put_chunk(pool, chunk); 582 + pool->available_elems += 1 << chunk->order; 339 583 mutex_unlock(&pool->lock); 340 584 } 341 585 ··· 357 599 pool->tbl_type = pool_attr->table_type; 358 600 pool->opt_type = pool_attr->opt_type; 359 601 360 - /* Support general db */ 361 - if (pool->flags == (MLX5HWS_POOL_FLAGS_RELEASE_FREE_RESOURCE | 362 - MLX5HWS_POOL_FLAGS_RESOURCE_PER_CHUNK)) 363 - res_db_type = MLX5HWS_POOL_DB_TYPE_GENERAL_SIZE; 364 - else if (pool->flags == (MLX5HWS_POOL_FLAGS_ONE_RESOURCE | 365 - MLX5HWS_POOL_FLAGS_FIXED_SIZE_OBJECTS)) 366 - res_db_type = MLX5HWS_POOL_DB_TYPE_ONE_SIZE_RESOURCE; 367 - else 602 + if (pool->flags & MLX5HWS_POOL_FLAG_BUDDY) 368 603 res_db_type = MLX5HWS_POOL_DB_TYPE_BUDDY; 604 + else 605 + res_db_type = MLX5HWS_POOL_DB_TYPE_BITMAP; 369 606 370 607 pool->alloc_log_sz = pool_attr->alloc_log_sz; 608 + pool->available_elems = 1 << pool_attr->alloc_log_sz; 371 609 372 610 if (hws_pool_db_init(pool, res_db_type)) 373 611 goto free_pool; ··· 377 623 return NULL; 378 624 } 379 625 380 - int mlx5hws_pool_destroy(struct mlx5hws_pool *pool) 626 + void mlx5hws_pool_destroy(struct mlx5hws_pool *pool) 381 627 { 382 - int i; 383 - 384 628 mutex_destroy(&pool->lock); 385 629 386 - for (i = 0; i < MLX5HWS_POOL_RESOURCE_ARR_SZ; i++) 387 - if (pool->resource[i]) 388 - hws_pool_resource_free(pool, i); 630 + if (pool->available_elems != 1 << pool->alloc_log_sz) 631 + mlx5hws_err(pool->ctx, "Attempting to destroy non-empty pool\n"); 632 + 633 + if (pool->resource) 634 + hws_pool_resource_free(pool); 389 635 390 636 hws_pool_db_unint(pool); 391 637 392 638 kfree(pool); 393 - return 0; 394 639 }
+42 -61
drivers/net/ethernet/mellanox/mlx5/core/steering/hws/pool.h
··· 6 6 7 7 #define MLX5HWS_POOL_STC_LOG_SZ 15 8 8 9 - #define MLX5HWS_POOL_RESOURCE_ARR_SZ 100 10 - 11 9 enum mlx5hws_pool_type { 12 10 MLX5HWS_POOL_TYPE_STE, 13 11 MLX5HWS_POOL_TYPE_STC, 14 12 }; 15 13 16 14 struct mlx5hws_pool_chunk { 17 - u32 resource_idx; 18 - /* Internal offset, relative to base index */ 19 15 int offset; 20 16 int order; 21 17 }; ··· 23 27 }; 24 28 25 29 enum mlx5hws_pool_flags { 26 - /* Only a one resource in that pool */ 27 - MLX5HWS_POOL_FLAGS_ONE_RESOURCE = 1 << 0, 28 - MLX5HWS_POOL_FLAGS_RELEASE_FREE_RESOURCE = 1 << 1, 29 - /* No sharing resources between chunks */ 30 - MLX5HWS_POOL_FLAGS_RESOURCE_PER_CHUNK = 1 << 2, 31 - /* All objects are in the same size */ 32 - MLX5HWS_POOL_FLAGS_FIXED_SIZE_OBJECTS = 1 << 3, 33 - /* Managed by buddy allocator */ 34 - MLX5HWS_POOL_FLAGS_BUDDY_MANAGED = 1 << 4, 35 - /* Allocate pool_type memory on pool creation */ 36 - MLX5HWS_POOL_FLAGS_ALLOC_MEM_ON_CREATE = 1 << 5, 37 - 38 - /* These values should be used by the caller */ 39 - MLX5HWS_POOL_FLAGS_FOR_STC_POOL = 40 - MLX5HWS_POOL_FLAGS_ONE_RESOURCE | 41 - MLX5HWS_POOL_FLAGS_FIXED_SIZE_OBJECTS, 42 - MLX5HWS_POOL_FLAGS_FOR_MATCHER_STE_POOL = 43 - MLX5HWS_POOL_FLAGS_RELEASE_FREE_RESOURCE | 44 - MLX5HWS_POOL_FLAGS_RESOURCE_PER_CHUNK, 45 - MLX5HWS_POOL_FLAGS_FOR_STE_ACTION_POOL = 46 - MLX5HWS_POOL_FLAGS_ONE_RESOURCE | 47 - MLX5HWS_POOL_FLAGS_BUDDY_MANAGED | 48 - MLX5HWS_POOL_FLAGS_ALLOC_MEM_ON_CREATE, 30 + /* Managed by a buddy allocator. If this is not set only allocations of 31 + * order 0 are supported. 32 + */ 33 + MLX5HWS_POOL_FLAG_BUDDY = BIT(0), 49 34 }; 50 35 51 36 enum mlx5hws_pool_optimize { 52 37 MLX5HWS_POOL_OPTIMIZE_NONE = 0x0, 53 38 MLX5HWS_POOL_OPTIMIZE_ORIG = 0x1, 54 39 MLX5HWS_POOL_OPTIMIZE_MIRROR = 0x2, 40 + MLX5HWS_POOL_OPTIMIZE_MAX = 0x3, 55 41 }; 56 42 57 43 struct mlx5hws_pool_attr { ··· 46 68 }; 47 69 48 70 enum mlx5hws_db_type { 49 - /* Uses for allocating chunk of big memory, each element has its own resource in the FW*/ 50 - MLX5HWS_POOL_DB_TYPE_GENERAL_SIZE, 51 - /* One resource only, all the elements are with same one size */ 52 - MLX5HWS_POOL_DB_TYPE_ONE_SIZE_RESOURCE, 53 - /* Many resources, the memory allocated with buddy mechanism */ 71 + /* Uses a bitmap, supports only allocations of order 0. */ 72 + MLX5HWS_POOL_DB_TYPE_BITMAP, 73 + /* Entries are managed using a buddy mechanism. */ 54 74 MLX5HWS_POOL_DB_TYPE_BUDDY, 55 - }; 56 - 57 - struct mlx5hws_buddy_manager { 58 - struct mlx5hws_buddy_mem *buddies[MLX5HWS_POOL_RESOURCE_ARR_SZ]; 59 - }; 60 - 61 - struct mlx5hws_pool_elements { 62 - u32 num_of_elements; 63 - unsigned long *bitmap; 64 - u32 log_size; 65 - bool is_full; 66 - }; 67 - 68 - struct mlx5hws_element_manager { 69 - struct mlx5hws_pool_elements *elements[MLX5HWS_POOL_RESOURCE_ARR_SZ]; 70 75 }; 71 76 72 77 struct mlx5hws_pool_db { 73 78 enum mlx5hws_db_type type; 74 79 union { 75 - struct mlx5hws_element_manager *element_manager; 76 - struct mlx5hws_buddy_manager *buddy_manager; 80 + unsigned long *bitmap; 81 + struct mlx5hws_buddy_mem *buddy; 77 82 }; 78 83 }; 79 84 ··· 72 111 enum mlx5hws_pool_flags flags; 73 112 struct mutex lock; /* protect the pool */ 74 113 size_t alloc_log_sz; 114 + size_t available_elems; 75 115 enum mlx5hws_table_type tbl_type; 76 116 enum mlx5hws_pool_optimize opt_type; 77 - struct mlx5hws_pool_resource *resource[MLX5HWS_POOL_RESOURCE_ARR_SZ]; 78 - struct mlx5hws_pool_resource *mirror_resource[MLX5HWS_POOL_RESOURCE_ARR_SZ]; 79 - /* DB */ 117 + struct mlx5hws_pool_resource *resource; 118 + struct mlx5hws_pool_resource *mirror_resource; 80 119 struct mlx5hws_pool_db db; 81 120 /* Functions */ 82 121 mlx5hws_pool_unint_db p_db_uninit; ··· 88 127 mlx5hws_pool_create(struct mlx5hws_context *ctx, 89 128 struct mlx5hws_pool_attr *pool_attr); 90 129 91 - int mlx5hws_pool_destroy(struct mlx5hws_pool *pool); 130 + void mlx5hws_pool_destroy(struct mlx5hws_pool *pool); 92 131 93 132 int mlx5hws_pool_chunk_alloc(struct mlx5hws_pool *pool, 94 133 struct mlx5hws_pool_chunk *chunk); ··· 96 135 void mlx5hws_pool_chunk_free(struct mlx5hws_pool *pool, 97 136 struct mlx5hws_pool_chunk *chunk); 98 137 99 - static inline u32 100 - mlx5hws_pool_chunk_get_base_id(struct mlx5hws_pool *pool, 101 - struct mlx5hws_pool_chunk *chunk) 138 + static inline u32 mlx5hws_pool_get_base_id(struct mlx5hws_pool *pool) 102 139 { 103 - return pool->resource[chunk->resource_idx]->base_id; 140 + return pool->resource->base_id; 104 141 } 105 142 106 - static inline u32 107 - mlx5hws_pool_chunk_get_base_mirror_id(struct mlx5hws_pool *pool, 108 - struct mlx5hws_pool_chunk *chunk) 143 + static inline u32 mlx5hws_pool_get_base_mirror_id(struct mlx5hws_pool *pool) 109 144 { 110 - return pool->mirror_resource[chunk->resource_idx]->base_id; 145 + return pool->mirror_resource->base_id; 146 + } 147 + 148 + static inline bool 149 + mlx5hws_pool_empty(struct mlx5hws_pool *pool) 150 + { 151 + bool ret; 152 + 153 + mutex_lock(&pool->lock); 154 + ret = pool->available_elems == 0; 155 + mutex_unlock(&pool->lock); 156 + 157 + return ret; 158 + } 159 + 160 + static inline bool 161 + mlx5hws_pool_full(struct mlx5hws_pool *pool) 162 + { 163 + bool ret; 164 + 165 + mutex_lock(&pool->lock); 166 + ret = pool->available_elems == (1 << pool->alloc_log_sz); 167 + mutex_unlock(&pool->lock); 168 + 169 + return ret; 111 170 } 112 171 #endif /* MLX5HWS_POOL_H_ */
+27 -42
drivers/net/ethernet/mellanox/mlx5/core/steering/hws/rule.c
··· 195 195 } 196 196 } 197 197 198 - static int hws_rule_alloc_action_ste(struct mlx5hws_rule *rule) 198 + static int mlx5hws_rule_alloc_action_ste(struct mlx5hws_rule *rule, 199 + u16 queue_id, bool skip_rx, 200 + bool skip_tx) 199 201 { 200 202 struct mlx5hws_matcher *matcher = rule->matcher; 201 - struct mlx5hws_matcher_action_ste *action_ste; 202 - struct mlx5hws_pool_chunk ste = {0}; 203 - int ret; 203 + struct mlx5hws_context *ctx = matcher->tbl->ctx; 204 204 205 - action_ste = &matcher->action_ste; 206 - ste.order = ilog2(roundup_pow_of_two(action_ste->max_stes)); 207 - ret = mlx5hws_pool_chunk_alloc(action_ste->pool, &ste); 208 - if (unlikely(ret)) { 209 - mlx5hws_err(matcher->tbl->ctx, 210 - "Failed to allocate STE for rule actions"); 211 - return ret; 212 - } 213 - 214 - rule->action_ste.pool = matcher->action_ste.pool; 215 - rule->action_ste.num_stes = matcher->action_ste.max_stes; 216 - rule->action_ste.index = ste.offset; 217 - 218 - return 0; 205 + rule->action_ste.ste.order = 206 + ilog2(roundup_pow_of_two(matcher->num_of_action_stes)); 207 + return mlx5hws_action_ste_chunk_alloc(&ctx->action_ste_pool[queue_id], 208 + skip_rx, skip_tx, 209 + &rule->action_ste); 219 210 } 220 211 221 - void mlx5hws_rule_free_action_ste(struct mlx5hws_rule_action_ste_info *action_ste) 212 + void mlx5hws_rule_free_action_ste(struct mlx5hws_action_ste_chunk *action_ste) 222 213 { 223 - struct mlx5hws_pool_chunk ste = {0}; 224 - 225 - if (!action_ste->num_stes) 214 + if (!action_ste->action_tbl) 226 215 return; 227 - 228 - ste.order = ilog2(roundup_pow_of_two(action_ste->num_stes)); 229 - ste.offset = action_ste->index; 230 216 231 217 /* This release is safe only when the rule match STE was deleted 232 218 * (when the rule is being deleted) or replaced with the new STE that 233 219 * isn't pointing to old action STEs (when the rule is being updated). 234 220 */ 235 - mlx5hws_pool_chunk_free(action_ste->pool, &ste); 221 + mlx5hws_action_ste_chunk_free(action_ste); 236 222 } 237 223 238 224 static void hws_rule_create_init(struct mlx5hws_rule *rule, ··· 236 250 rule->rtc_0 = 0; 237 251 rule->rtc_1 = 0; 238 252 239 - rule->action_ste.pool = NULL; 240 - rule->action_ste.num_stes = 0; 241 - rule->action_ste.index = -1; 242 - 243 253 rule->status = MLX5HWS_RULE_STATUS_CREATING; 244 254 } else { 245 255 rule->status = MLX5HWS_RULE_STATUS_UPDATING; 256 + /* Save the old action STE info so we can free it after writing 257 + * new action STEs and a corresponding match STE. 258 + */ 259 + rule->old_action_ste = rule->action_ste; 246 260 } 247 - 248 - /* Initialize the old action STE info - shallow-copy action_ste. 249 - * In create flow this will set old_action_ste fields to initial values. 250 - * In update flow this will save the existing action STE info, 251 - * so that we will later use it to free old STEs. 252 - */ 253 - rule->old_action_ste = rule->action_ste; 254 261 255 262 rule->pending_wqes = 0; 256 263 ··· 256 277 /* Init default action apply */ 257 278 apply->tbl_type = tbl->type; 258 279 apply->common_res = &ctx->common_res; 259 - apply->jump_to_action_stc = matcher->action_ste.stc.offset; 260 280 apply->require_dep = 0; 261 281 } 262 282 ··· 331 353 332 354 if (action_stes) { 333 355 /* Allocate action STEs for rules that need more than match STE */ 334 - ret = hws_rule_alloc_action_ste(rule); 356 + ret = mlx5hws_rule_alloc_action_ste(rule, attr->queue_id, 357 + !!ste_attr.rtc_0, 358 + !!ste_attr.rtc_1); 335 359 if (ret) { 336 360 mlx5hws_err(ctx, "Failed to allocate action memory %d", ret); 337 361 mlx5hws_send_abort_new_dep_wqe(queue); 338 362 return ret; 339 363 } 364 + apply.jump_to_action_stc = 365 + rule->action_ste.action_tbl->stc.offset; 340 366 /* Skip RX/TX based on the dep_wqe init */ 341 - ste_attr.rtc_0 = dep_wqe->rtc_0 ? matcher->action_ste.rtc_0_id : 0; 342 - ste_attr.rtc_1 = dep_wqe->rtc_1 ? matcher->action_ste.rtc_1_id : 0; 367 + ste_attr.rtc_0 = dep_wqe->rtc_0 ? 368 + rule->action_ste.action_tbl->rtc_0_id : 0; 369 + ste_attr.rtc_1 = dep_wqe->rtc_1 ? 370 + rule->action_ste.action_tbl->rtc_1_id : 0; 343 371 /* Action STEs are written to a specific index last to first */ 344 - ste_attr.direct_index = rule->action_ste.index + action_stes; 372 + ste_attr.direct_index = 373 + rule->action_ste.ste.offset + action_stes; 345 374 apply.next_direct_idx = ste_attr.direct_index; 346 375 } else { 347 376 apply.next_direct_idx = 0;
+3 -9
drivers/net/ethernet/mellanox/mlx5/core/steering/hws/rule.h
··· 43 43 }; 44 44 }; 45 45 46 - struct mlx5hws_rule_action_ste_info { 47 - struct mlx5hws_pool *pool; 48 - int index; /* STE array index */ 49 - u8 num_stes; 50 - }; 51 - 52 46 struct mlx5hws_rule_resize_info { 53 47 u32 rtc_0; 54 48 u32 rtc_1; ··· 58 64 struct mlx5hws_rule_match_tag tag; 59 65 struct mlx5hws_rule_resize_info *resize_info; 60 66 }; 61 - struct mlx5hws_rule_action_ste_info action_ste; 62 - struct mlx5hws_rule_action_ste_info old_action_ste; 67 + struct mlx5hws_action_ste_chunk action_ste; 68 + struct mlx5hws_action_ste_chunk old_action_ste; 63 69 u32 rtc_0; /* The RTC into which the STE was inserted */ 64 70 u32 rtc_1; /* The RTC into which the STE was inserted */ 65 71 u8 status; /* enum mlx5hws_rule_status */ ··· 69 75 */ 70 76 }; 71 77 72 - void mlx5hws_rule_free_action_ste(struct mlx5hws_rule_action_ste_info *action_ste); 78 + void mlx5hws_rule_free_action_ste(struct mlx5hws_action_ste_chunk *action_ste); 73 79 74 80 int mlx5hws_rule_move_hws_remove(struct mlx5hws_rule *rule, 75 81 void *queue, void *user_data);