1 /*
2  * drivers/net/ethernet/mellanox/mlxsw/spectrum1_acl_tcam.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/slab.h>
37 
38 #include "reg.h"
39 #include "core.h"
40 #include "spectrum.h"
41 #include "spectrum_acl_tcam.h"
42 
43 struct mlxsw_sp1_acl_tcam_region {
44 	struct mlxsw_sp_acl_ctcam_region cregion;
45 	struct mlxsw_sp_acl_tcam_region *region;
46 	struct {
47 		struct mlxsw_sp_acl_ctcam_chunk cchunk;
48 		struct mlxsw_sp_acl_ctcam_entry centry;
49 		struct mlxsw_sp_acl_rule_info *rulei;
50 	} catchall;
51 };
52 
53 struct mlxsw_sp1_acl_tcam_chunk {
54 	struct mlxsw_sp_acl_ctcam_chunk cchunk;
55 };
56 
57 struct mlxsw_sp1_acl_tcam_entry {
58 	struct mlxsw_sp_acl_ctcam_entry centry;
59 };
60 
61 static int mlxsw_sp1_acl_tcam_init(struct mlxsw_sp *mlxsw_sp, void *priv,
62 				   struct mlxsw_sp_acl_tcam *tcam)
63 {
64 	return 0;
65 }
66 
67 static void mlxsw_sp1_acl_tcam_fini(struct mlxsw_sp *mlxsw_sp, void *priv)
68 {
69 }
70 
71 static int
72 mlxsw_sp1_acl_ctcam_region_catchall_add(struct mlxsw_sp *mlxsw_sp,
73 					struct mlxsw_sp1_acl_tcam_region *region)
74 {
75 	struct mlxsw_sp_acl_rule_info *rulei;
76 	int err;
77 
78 	mlxsw_sp_acl_ctcam_chunk_init(&region->cregion,
79 				      &region->catchall.cchunk,
80 				      MLXSW_SP_ACL_TCAM_CATCHALL_PRIO);
81 	rulei = mlxsw_sp_acl_rulei_create(mlxsw_sp->acl);
82 	if (IS_ERR(rulei)) {
83 		err = PTR_ERR(rulei);
84 		goto err_rulei_create;
85 	}
86 	err = mlxsw_sp_acl_rulei_act_continue(rulei);
87 	if (WARN_ON(err))
88 		goto err_rulei_act_continue;
89 	err = mlxsw_sp_acl_rulei_commit(rulei);
90 	if (err)
91 		goto err_rulei_commit;
92 	err = mlxsw_sp_acl_ctcam_entry_add(mlxsw_sp, &region->cregion,
93 					   &region->catchall.cchunk,
94 					   &region->catchall.centry,
95 					   rulei, false);
96 	if (err)
97 		goto err_entry_add;
98 	region->catchall.rulei = rulei;
99 	return 0;
100 
101 err_entry_add:
102 err_rulei_commit:
103 err_rulei_act_continue:
104 	mlxsw_sp_acl_rulei_destroy(rulei);
105 err_rulei_create:
106 	mlxsw_sp_acl_ctcam_chunk_fini(&region->catchall.cchunk);
107 	return err;
108 }
109 
110 static void
111 mlxsw_sp1_acl_ctcam_region_catchall_del(struct mlxsw_sp *mlxsw_sp,
112 					struct mlxsw_sp1_acl_tcam_region *region)
113 {
114 	struct mlxsw_sp_acl_rule_info *rulei = region->catchall.rulei;
115 
116 	mlxsw_sp_acl_ctcam_entry_del(mlxsw_sp, &region->cregion,
117 				     &region->catchall.cchunk,
118 				     &region->catchall.centry);
119 	mlxsw_sp_acl_rulei_destroy(rulei);
120 	mlxsw_sp_acl_ctcam_chunk_fini(&region->catchall.cchunk);
121 }
122 
123 static int
124 mlxsw_sp1_acl_tcam_region_init(struct mlxsw_sp *mlxsw_sp, void *region_priv,
125 			       struct mlxsw_sp_acl_tcam_region *_region)
126 {
127 	struct mlxsw_sp1_acl_tcam_region *region = region_priv;
128 	int err;
129 
130 	err = mlxsw_sp_acl_ctcam_region_init(mlxsw_sp, &region->cregion,
131 					     _region);
132 	if (err)
133 		return err;
134 	err = mlxsw_sp1_acl_ctcam_region_catchall_add(mlxsw_sp, region);
135 	if (err)
136 		goto err_catchall_add;
137 	region->region = _region;
138 	return 0;
139 
140 err_catchall_add:
141 	mlxsw_sp_acl_ctcam_region_fini(&region->cregion);
142 	return err;
143 }
144 
145 static void
146 mlxsw_sp1_acl_tcam_region_fini(struct mlxsw_sp *mlxsw_sp, void *region_priv)
147 {
148 	struct mlxsw_sp1_acl_tcam_region *region = region_priv;
149 
150 	mlxsw_sp1_acl_ctcam_region_catchall_del(mlxsw_sp, region);
151 	mlxsw_sp_acl_ctcam_region_fini(&region->cregion);
152 }
153 
154 static int
155 mlxsw_sp1_acl_tcam_region_associate(struct mlxsw_sp *mlxsw_sp,
156 				    struct mlxsw_sp_acl_tcam_region *region)
157 {
158 	return 0;
159 }
160 
161 static void mlxsw_sp1_acl_tcam_chunk_init(void *region_priv, void *chunk_priv,
162 					  unsigned int priority)
163 {
164 	struct mlxsw_sp1_acl_tcam_region *region = region_priv;
165 	struct mlxsw_sp1_acl_tcam_chunk *chunk = chunk_priv;
166 
167 	mlxsw_sp_acl_ctcam_chunk_init(&region->cregion, &chunk->cchunk,
168 				      priority);
169 }
170 
171 static void mlxsw_sp1_acl_tcam_chunk_fini(void *chunk_priv)
172 {
173 	struct mlxsw_sp1_acl_tcam_chunk *chunk = chunk_priv;
174 
175 	mlxsw_sp_acl_ctcam_chunk_fini(&chunk->cchunk);
176 }
177 
178 static int mlxsw_sp1_acl_tcam_entry_add(struct mlxsw_sp *mlxsw_sp,
179 					void *region_priv, void *chunk_priv,
180 					void *entry_priv,
181 					struct mlxsw_sp_acl_rule_info *rulei)
182 {
183 	struct mlxsw_sp1_acl_tcam_region *region = region_priv;
184 	struct mlxsw_sp1_acl_tcam_chunk *chunk = chunk_priv;
185 	struct mlxsw_sp1_acl_tcam_entry *entry = entry_priv;
186 
187 	return mlxsw_sp_acl_ctcam_entry_add(mlxsw_sp, &region->cregion,
188 					    &chunk->cchunk, &entry->centry,
189 					    rulei, false);
190 }
191 
192 static void mlxsw_sp1_acl_tcam_entry_del(struct mlxsw_sp *mlxsw_sp,
193 					 void *region_priv, void *chunk_priv,
194 					 void *entry_priv)
195 {
196 	struct mlxsw_sp1_acl_tcam_region *region = region_priv;
197 	struct mlxsw_sp1_acl_tcam_chunk *chunk = chunk_priv;
198 	struct mlxsw_sp1_acl_tcam_entry *entry = entry_priv;
199 
200 	mlxsw_sp_acl_ctcam_entry_del(mlxsw_sp, &region->cregion,
201 				     &chunk->cchunk, &entry->centry);
202 }
203 
204 static int
205 mlxsw_sp1_acl_tcam_region_entry_activity_get(struct mlxsw_sp *mlxsw_sp,
206 					     struct mlxsw_sp_acl_tcam_region *_region,
207 					     unsigned int offset,
208 					     bool *activity)
209 {
210 	char ptce2_pl[MLXSW_REG_PTCE2_LEN];
211 	int err;
212 
213 	mlxsw_reg_ptce2_pack(ptce2_pl, true, MLXSW_REG_PTCE2_OP_QUERY_CLEAR_ON_READ,
214 			     _region->tcam_region_info, offset, 0);
215 	err = mlxsw_reg_query(mlxsw_sp->core, MLXSW_REG(ptce2), ptce2_pl);
216 	if (err)
217 		return err;
218 	*activity = mlxsw_reg_ptce2_a_get(ptce2_pl);
219 	return 0;
220 }
221 
222 static int
223 mlxsw_sp1_acl_tcam_entry_activity_get(struct mlxsw_sp *mlxsw_sp,
224 				      void *region_priv, void *entry_priv,
225 				      bool *activity)
226 {
227 	struct mlxsw_sp1_acl_tcam_region *region = region_priv;
228 	struct mlxsw_sp1_acl_tcam_entry *entry = entry_priv;
229 	unsigned int offset;
230 
231 	offset = mlxsw_sp_acl_ctcam_entry_offset(&entry->centry);
232 	return mlxsw_sp1_acl_tcam_region_entry_activity_get(mlxsw_sp,
233 							    region->region,
234 							    offset, activity);
235 }
236 
237 const struct mlxsw_sp_acl_tcam_ops mlxsw_sp1_acl_tcam_ops = {
238 	.key_type		= MLXSW_REG_PTAR_KEY_TYPE_FLEX,
239 	.priv_size		= 0,
240 	.init			= mlxsw_sp1_acl_tcam_init,
241 	.fini			= mlxsw_sp1_acl_tcam_fini,
242 	.region_priv_size	= sizeof(struct mlxsw_sp1_acl_tcam_region),
243 	.region_init		= mlxsw_sp1_acl_tcam_region_init,
244 	.region_fini		= mlxsw_sp1_acl_tcam_region_fini,
245 	.region_associate	= mlxsw_sp1_acl_tcam_region_associate,
246 	.chunk_priv_size	= sizeof(struct mlxsw_sp1_acl_tcam_chunk),
247 	.chunk_init		= mlxsw_sp1_acl_tcam_chunk_init,
248 	.chunk_fini		= mlxsw_sp1_acl_tcam_chunk_fini,
249 	.entry_priv_size	= sizeof(struct mlxsw_sp1_acl_tcam_entry),
250 	.entry_add		= mlxsw_sp1_acl_tcam_entry_add,
251 	.entry_del		= mlxsw_sp1_acl_tcam_entry_del,
252 	.entry_activity_get	= mlxsw_sp1_acl_tcam_entry_activity_get,
253 };
254