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 void mlxsw_sp1_acl_tcam_chunk_init(void *region_priv, void *chunk_priv,
155 					  unsigned int priority)
156 {
157 	struct mlxsw_sp1_acl_tcam_region *region = region_priv;
158 	struct mlxsw_sp1_acl_tcam_chunk *chunk = chunk_priv;
159 
160 	mlxsw_sp_acl_ctcam_chunk_init(&region->cregion, &chunk->cchunk,
161 				      priority);
162 }
163 
164 static void mlxsw_sp1_acl_tcam_chunk_fini(void *chunk_priv)
165 {
166 	struct mlxsw_sp1_acl_tcam_chunk *chunk = chunk_priv;
167 
168 	mlxsw_sp_acl_ctcam_chunk_fini(&chunk->cchunk);
169 }
170 
171 static int mlxsw_sp1_acl_tcam_entry_add(struct mlxsw_sp *mlxsw_sp,
172 					void *region_priv, void *chunk_priv,
173 					void *entry_priv,
174 					struct mlxsw_sp_acl_rule_info *rulei)
175 {
176 	struct mlxsw_sp1_acl_tcam_region *region = region_priv;
177 	struct mlxsw_sp1_acl_tcam_chunk *chunk = chunk_priv;
178 	struct mlxsw_sp1_acl_tcam_entry *entry = entry_priv;
179 
180 	return mlxsw_sp_acl_ctcam_entry_add(mlxsw_sp, &region->cregion,
181 					    &chunk->cchunk, &entry->centry,
182 					    rulei, false);
183 }
184 
185 static void mlxsw_sp1_acl_tcam_entry_del(struct mlxsw_sp *mlxsw_sp,
186 					 void *region_priv, void *chunk_priv,
187 					 void *entry_priv)
188 {
189 	struct mlxsw_sp1_acl_tcam_region *region = region_priv;
190 	struct mlxsw_sp1_acl_tcam_chunk *chunk = chunk_priv;
191 	struct mlxsw_sp1_acl_tcam_entry *entry = entry_priv;
192 
193 	mlxsw_sp_acl_ctcam_entry_del(mlxsw_sp, &region->cregion,
194 				     &chunk->cchunk, &entry->centry);
195 }
196 
197 static int
198 mlxsw_sp1_acl_tcam_region_entry_activity_get(struct mlxsw_sp *mlxsw_sp,
199 					     struct mlxsw_sp_acl_tcam_region *_region,
200 					     unsigned int offset,
201 					     bool *activity)
202 {
203 	char ptce2_pl[MLXSW_REG_PTCE2_LEN];
204 	int err;
205 
206 	mlxsw_reg_ptce2_pack(ptce2_pl, true, MLXSW_REG_PTCE2_OP_QUERY_CLEAR_ON_READ,
207 			     _region->tcam_region_info, offset, 0);
208 	err = mlxsw_reg_query(mlxsw_sp->core, MLXSW_REG(ptce2), ptce2_pl);
209 	if (err)
210 		return err;
211 	*activity = mlxsw_reg_ptce2_a_get(ptce2_pl);
212 	return 0;
213 }
214 
215 static int
216 mlxsw_sp1_acl_tcam_entry_activity_get(struct mlxsw_sp *mlxsw_sp,
217 				      void *region_priv, void *entry_priv,
218 				      bool *activity)
219 {
220 	struct mlxsw_sp1_acl_tcam_region *region = region_priv;
221 	struct mlxsw_sp1_acl_tcam_entry *entry = entry_priv;
222 	unsigned int offset;
223 
224 	offset = mlxsw_sp_acl_ctcam_entry_offset(&entry->centry);
225 	return mlxsw_sp1_acl_tcam_region_entry_activity_get(mlxsw_sp,
226 							    region->region,
227 							    offset, activity);
228 }
229 
230 const struct mlxsw_sp_acl_tcam_ops mlxsw_sp1_acl_tcam_ops = {
231 	.key_type		= MLXSW_REG_PTAR_KEY_TYPE_FLEX,
232 	.priv_size		= 0,
233 	.init			= mlxsw_sp1_acl_tcam_init,
234 	.fini			= mlxsw_sp1_acl_tcam_fini,
235 	.region_priv_size	= sizeof(struct mlxsw_sp1_acl_tcam_region),
236 	.region_init		= mlxsw_sp1_acl_tcam_region_init,
237 	.region_fini		= mlxsw_sp1_acl_tcam_region_fini,
238 	.chunk_priv_size	= sizeof(struct mlxsw_sp1_acl_tcam_chunk),
239 	.chunk_init		= mlxsw_sp1_acl_tcam_chunk_init,
240 	.chunk_fini		= mlxsw_sp1_acl_tcam_chunk_fini,
241 	.entry_priv_size	= sizeof(struct mlxsw_sp1_acl_tcam_entry),
242 	.entry_add		= mlxsw_sp1_acl_tcam_entry_add,
243 	.entry_del		= mlxsw_sp1_acl_tcam_entry_del,
244 	.entry_activity_get	= mlxsw_sp1_acl_tcam_entry_activity_get,
245 };
246