]>
Commit | Line | Data |
---|---|---|
64eccd00 JP |
1 | /* |
2 | * drivers/net/ethernet/mellanox/mlxsw/spectrum_acl_ctcam.c | |
3 | * Copyright (c) 2017-2018 Mellanox Technologies. All rights reserved. | |
4 | * Copyright (c) 2017-2018 Jiri Pirko <jiri@mellanox.com> | |
5 | * | |
6 | * Redistribution and use in source and binary forms, with or without | |
7 | * modification, are permitted provided that the following conditions are met: | |
8 | * | |
9 | * 1. Redistributions of source code must retain the above copyright | |
10 | * notice, this list of conditions and the following disclaimer. | |
11 | * 2. Redistributions in binary form must reproduce the above copyright | |
12 | * notice, this list of conditions and the following disclaimer in the | |
13 | * documentation and/or other materials provided with the distribution. | |
14 | * 3. Neither the names of the copyright holders nor the names of its | |
15 | * contributors may be used to endorse or promote products derived from | |
16 | * this software without specific prior written permission. | |
17 | * | |
18 | * Alternatively, this software may be distributed under the terms of the | |
19 | * GNU General Public License ("GPL") version 2 as published by the Free | |
20 | * Software Foundation. | |
21 | * | |
22 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" | |
23 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |
24 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | |
25 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE | |
26 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | |
27 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | |
28 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS | |
29 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN | |
30 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | |
31 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | |
32 | * POSSIBILITY OF SUCH DAMAGE. | |
33 | */ | |
34 | ||
35 | #include <linux/kernel.h> | |
36 | #include <linux/errno.h> | |
37 | #include <linux/parman.h> | |
38 | ||
39 | #include "reg.h" | |
40 | #include "core.h" | |
41 | #include "spectrum.h" | |
42 | #include "spectrum_acl_tcam.h" | |
43 | ||
44 | static int | |
45 | mlxsw_sp_acl_ctcam_region_resize(struct mlxsw_sp *mlxsw_sp, | |
46 | struct mlxsw_sp_acl_tcam_region *region, | |
47 | u16 new_size) | |
48 | { | |
49 | char ptar_pl[MLXSW_REG_PTAR_LEN]; | |
50 | ||
51 | mlxsw_reg_ptar_pack(ptar_pl, MLXSW_REG_PTAR_OP_RESIZE, | |
52 | region->key_type, new_size, region->id, | |
53 | region->tcam_region_info); | |
54 | return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(ptar), ptar_pl); | |
55 | } | |
56 | ||
57 | static void | |
58 | mlxsw_sp_acl_ctcam_region_move(struct mlxsw_sp *mlxsw_sp, | |
59 | struct mlxsw_sp_acl_tcam_region *region, | |
60 | u16 src_offset, u16 dst_offset, u16 size) | |
61 | { | |
62 | char prcr_pl[MLXSW_REG_PRCR_LEN]; | |
63 | ||
64 | mlxsw_reg_prcr_pack(prcr_pl, MLXSW_REG_PRCR_OP_MOVE, | |
65 | region->tcam_region_info, src_offset, | |
66 | region->tcam_region_info, dst_offset, size); | |
67 | mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(prcr), prcr_pl); | |
68 | } | |
69 | ||
70 | static int | |
71 | mlxsw_sp_acl_ctcam_region_entry_insert(struct mlxsw_sp *mlxsw_sp, | |
72 | struct mlxsw_sp_acl_tcam_region *region, | |
73 | unsigned int offset, | |
74 | struct mlxsw_sp_acl_rule_info *rulei) | |
75 | { | |
76 | char ptce2_pl[MLXSW_REG_PTCE2_LEN]; | |
77 | char *act_set; | |
78 | char *mask; | |
79 | char *key; | |
80 | ||
81 | mlxsw_reg_ptce2_pack(ptce2_pl, true, MLXSW_REG_PTCE2_OP_WRITE_WRITE, | |
82 | region->tcam_region_info, offset); | |
83 | key = mlxsw_reg_ptce2_flex_key_blocks_data(ptce2_pl); | |
84 | mask = mlxsw_reg_ptce2_mask_data(ptce2_pl); | |
85 | mlxsw_afk_encode(region->key_info, &rulei->values, key, mask); | |
86 | ||
87 | /* Only the first action set belongs here, the rest is in KVD */ | |
88 | act_set = mlxsw_afa_block_first_set(rulei->act_block); | |
89 | mlxsw_reg_ptce2_flex_action_set_memcpy_to(ptce2_pl, act_set); | |
90 | ||
91 | return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(ptce2), ptce2_pl); | |
92 | } | |
93 | ||
94 | static void | |
95 | mlxsw_sp_acl_ctcam_region_entry_remove(struct mlxsw_sp *mlxsw_sp, | |
96 | struct mlxsw_sp_acl_tcam_region *region, | |
97 | unsigned int offset) | |
98 | { | |
99 | char ptce2_pl[MLXSW_REG_PTCE2_LEN]; | |
100 | ||
101 | mlxsw_reg_ptce2_pack(ptce2_pl, false, MLXSW_REG_PTCE2_OP_WRITE_WRITE, | |
102 | region->tcam_region_info, offset); | |
103 | mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(ptce2), ptce2_pl); | |
104 | } | |
105 | ||
106 | static int mlxsw_sp_acl_ctcam_region_parman_resize(void *priv, | |
107 | unsigned long new_count) | |
108 | { | |
109 | struct mlxsw_sp_acl_ctcam_region *cregion = priv; | |
110 | struct mlxsw_sp_acl_tcam_region *region = cregion->region; | |
111 | struct mlxsw_sp *mlxsw_sp = region->mlxsw_sp; | |
112 | u64 max_tcam_rules; | |
113 | ||
114 | max_tcam_rules = MLXSW_CORE_RES_GET(mlxsw_sp->core, ACL_MAX_TCAM_RULES); | |
115 | if (new_count > max_tcam_rules) | |
116 | return -EINVAL; | |
117 | return mlxsw_sp_acl_ctcam_region_resize(mlxsw_sp, region, new_count); | |
118 | } | |
119 | ||
120 | static void mlxsw_sp_acl_ctcam_region_parman_move(void *priv, | |
121 | unsigned long from_index, | |
122 | unsigned long to_index, | |
123 | unsigned long count) | |
124 | { | |
125 | struct mlxsw_sp_acl_ctcam_region *cregion = priv; | |
126 | struct mlxsw_sp_acl_tcam_region *region = cregion->region; | |
127 | struct mlxsw_sp *mlxsw_sp = region->mlxsw_sp; | |
128 | ||
129 | mlxsw_sp_acl_ctcam_region_move(mlxsw_sp, region, | |
130 | from_index, to_index, count); | |
131 | } | |
132 | ||
133 | static const struct parman_ops mlxsw_sp_acl_ctcam_region_parman_ops = { | |
134 | .base_count = MLXSW_SP_ACL_TCAM_REGION_BASE_COUNT, | |
135 | .resize_step = MLXSW_SP_ACL_TCAM_REGION_RESIZE_STEP, | |
136 | .resize = mlxsw_sp_acl_ctcam_region_parman_resize, | |
137 | .move = mlxsw_sp_acl_ctcam_region_parman_move, | |
138 | .algo = PARMAN_ALGO_TYPE_LSORT, | |
139 | }; | |
140 | ||
141 | int mlxsw_sp_acl_ctcam_region_init(struct mlxsw_sp *mlxsw_sp, | |
142 | struct mlxsw_sp_acl_ctcam_region *cregion, | |
143 | struct mlxsw_sp_acl_tcam_region *region) | |
144 | { | |
145 | cregion->region = region; | |
146 | cregion->parman = parman_create(&mlxsw_sp_acl_ctcam_region_parman_ops, | |
147 | cregion); | |
148 | if (!cregion->parman) | |
149 | return -ENOMEM; | |
150 | return 0; | |
151 | } | |
152 | ||
153 | void mlxsw_sp_acl_ctcam_region_fini(struct mlxsw_sp_acl_ctcam_region *cregion) | |
154 | { | |
155 | parman_destroy(cregion->parman); | |
156 | } | |
157 | ||
158 | void mlxsw_sp_acl_ctcam_chunk_init(struct mlxsw_sp_acl_ctcam_region *cregion, | |
159 | struct mlxsw_sp_acl_ctcam_chunk *cchunk, | |
160 | unsigned int priority) | |
161 | { | |
162 | parman_prio_init(cregion->parman, &cchunk->parman_prio, priority); | |
163 | } | |
164 | ||
165 | void mlxsw_sp_acl_ctcam_chunk_fini(struct mlxsw_sp_acl_ctcam_chunk *cchunk) | |
166 | { | |
167 | parman_prio_fini(&cchunk->parman_prio); | |
168 | } | |
169 | ||
170 | int mlxsw_sp_acl_ctcam_entry_add(struct mlxsw_sp *mlxsw_sp, | |
171 | struct mlxsw_sp_acl_ctcam_region *cregion, | |
172 | struct mlxsw_sp_acl_ctcam_chunk *cchunk, | |
173 | struct mlxsw_sp_acl_ctcam_entry *centry, | |
174 | struct mlxsw_sp_acl_rule_info *rulei) | |
175 | { | |
176 | int err; | |
177 | ||
178 | err = parman_item_add(cregion->parman, &cchunk->parman_prio, | |
179 | ¢ry->parman_item); | |
180 | if (err) | |
181 | return err; | |
182 | ||
183 | err = mlxsw_sp_acl_ctcam_region_entry_insert(mlxsw_sp, cregion->region, | |
184 | centry->parman_item.index, | |
185 | rulei); | |
186 | if (err) | |
187 | goto err_rule_insert; | |
188 | return 0; | |
189 | ||
190 | err_rule_insert: | |
191 | parman_item_remove(cregion->parman, &cchunk->parman_prio, | |
192 | ¢ry->parman_item); | |
193 | return err; | |
194 | } | |
195 | ||
196 | void mlxsw_sp_acl_ctcam_entry_del(struct mlxsw_sp *mlxsw_sp, | |
197 | struct mlxsw_sp_acl_ctcam_region *cregion, | |
198 | struct mlxsw_sp_acl_ctcam_chunk *cchunk, | |
199 | struct mlxsw_sp_acl_ctcam_entry *centry) | |
200 | { | |
201 | mlxsw_sp_acl_ctcam_region_entry_remove(mlxsw_sp, cregion->region, | |
202 | centry->parman_item.index); | |
203 | parman_item_remove(cregion->parman, &cchunk->parman_prio, | |
204 | ¢ry->parman_item); | |
205 | } |