33787b154e7463f756f688aa4ec92ff475897d5d
[platform/kernel/linux-rpi.git] / drivers / net / ethernet / mellanox / mlxsw / spectrum2_acl_tcam.c
1 /*
2  * drivers/net/ethernet/mellanox/mlxsw/spectrum2_acl_tcam.c
3  * Copyright (c) 2018 Mellanox Technologies. All rights reserved.
4  * Copyright (c) 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
37 #include "spectrum.h"
38 #include "spectrum_acl_tcam.h"
39 #include "core_acl_flex_actions.h"
40
41 struct mlxsw_sp2_acl_tcam {
42         u32 kvdl_index;
43         unsigned int kvdl_count;
44 };
45
46 struct mlxsw_sp2_acl_tcam_region {
47         struct mlxsw_sp_acl_ctcam_region cregion;
48         struct mlxsw_sp_acl_tcam_region *region;
49 };
50
51 struct mlxsw_sp2_acl_tcam_chunk {
52         struct mlxsw_sp_acl_ctcam_chunk cchunk;
53 };
54
55 struct mlxsw_sp2_acl_tcam_entry {
56         struct mlxsw_sp_acl_ctcam_entry centry;
57         struct mlxsw_afa_block *act_block;
58 };
59
60 static int mlxsw_sp2_acl_tcam_init(struct mlxsw_sp *mlxsw_sp, void *priv,
61                                    struct mlxsw_sp_acl_tcam *_tcam)
62 {
63         struct mlxsw_sp2_acl_tcam *tcam = priv;
64         struct mlxsw_afa_block *afa_block;
65         char pefa_pl[MLXSW_REG_PEFA_LEN];
66         char pgcr_pl[MLXSW_REG_PGCR_LEN];
67         char *enc_actions;
68         int i;
69         int err;
70
71         tcam->kvdl_count = _tcam->max_regions;
72         err = mlxsw_sp_kvdl_alloc(mlxsw_sp, MLXSW_SP_KVDL_ENTRY_TYPE_ACTSET,
73                                   tcam->kvdl_count, &tcam->kvdl_index);
74         if (err)
75                 return err;
76
77         /* Create flex action block, set default action (continue)
78          * but don't commit. We need just the current set encoding
79          * to be written using PEFA register to all indexes for all regions.
80          */
81         afa_block = mlxsw_afa_block_create(mlxsw_sp->afa);
82         if (!afa_block) {
83                 err = -ENOMEM;
84                 goto err_afa_block;
85         }
86         err = mlxsw_afa_block_continue(afa_block);
87         if (WARN_ON(err))
88                 goto err_afa_block_continue;
89         enc_actions = mlxsw_afa_block_cur_set(afa_block);
90
91         for (i = 0; i < tcam->kvdl_count; i++) {
92                 mlxsw_reg_pefa_pack(pefa_pl, tcam->kvdl_index + i,
93                                     true, enc_actions);
94                 err = mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(pefa), pefa_pl);
95                 if (err)
96                         goto err_pefa_write;
97         }
98         mlxsw_reg_pgcr_pack(pgcr_pl, tcam->kvdl_index);
99         err = mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(pgcr), pgcr_pl);
100         if (err)
101                 goto err_pgcr_write;
102
103         mlxsw_afa_block_destroy(afa_block);
104         return 0;
105
106 err_pgcr_write:
107 err_pefa_write:
108 err_afa_block_continue:
109         mlxsw_afa_block_destroy(afa_block);
110 err_afa_block:
111         mlxsw_sp_kvdl_free(mlxsw_sp, MLXSW_SP_KVDL_ENTRY_TYPE_ACTSET,
112                            tcam->kvdl_count, tcam->kvdl_index);
113         return err;
114 }
115
116 static void mlxsw_sp2_acl_tcam_fini(struct mlxsw_sp *mlxsw_sp, void *priv)
117 {
118         struct mlxsw_sp2_acl_tcam *tcam = priv;
119
120         mlxsw_sp_kvdl_free(mlxsw_sp, MLXSW_SP_KVDL_ENTRY_TYPE_ACTSET,
121                            tcam->kvdl_count, tcam->kvdl_index);
122 }
123
124 static int
125 mlxsw_sp2_acl_tcam_region_init(struct mlxsw_sp *mlxsw_sp, void *region_priv,
126                                struct mlxsw_sp_acl_tcam_region *_region)
127 {
128         struct mlxsw_sp2_acl_tcam_region *region = region_priv;
129         int err;
130
131         region->region = _region;
132
133         err = mlxsw_sp_acl_atcam_region_init(mlxsw_sp, _region);
134         if (err)
135                 return err;
136         return mlxsw_sp_acl_ctcam_region_init(mlxsw_sp, &region->cregion,
137                                               _region);
138 }
139
140 static void
141 mlxsw_sp2_acl_tcam_region_fini(struct mlxsw_sp *mlxsw_sp, void *region_priv)
142 {
143         struct mlxsw_sp2_acl_tcam_region *region = region_priv;
144
145         mlxsw_sp_acl_ctcam_region_fini(&region->cregion);
146 }
147
148 static int
149 mlxsw_sp2_acl_tcam_region_associate(struct mlxsw_sp *mlxsw_sp,
150                                     struct mlxsw_sp_acl_tcam_region *region)
151 {
152         return mlxsw_sp_acl_atcam_region_associate(mlxsw_sp, region->id);
153 }
154
155 static void mlxsw_sp2_acl_tcam_chunk_init(void *region_priv, void *chunk_priv,
156                                           unsigned int priority)
157 {
158         struct mlxsw_sp2_acl_tcam_region *region = region_priv;
159         struct mlxsw_sp2_acl_tcam_chunk *chunk = chunk_priv;
160
161         mlxsw_sp_acl_ctcam_chunk_init(&region->cregion, &chunk->cchunk,
162                                       priority);
163 }
164
165 static void mlxsw_sp2_acl_tcam_chunk_fini(void *chunk_priv)
166 {
167         struct mlxsw_sp2_acl_tcam_chunk *chunk = chunk_priv;
168
169         mlxsw_sp_acl_ctcam_chunk_fini(&chunk->cchunk);
170 }
171
172 static int mlxsw_sp2_acl_tcam_entry_add(struct mlxsw_sp *mlxsw_sp,
173                                         void *region_priv, void *chunk_priv,
174                                         void *entry_priv,
175                                         struct mlxsw_sp_acl_rule_info *rulei)
176 {
177         struct mlxsw_sp2_acl_tcam_region *region = region_priv;
178         struct mlxsw_sp2_acl_tcam_chunk *chunk = chunk_priv;
179         struct mlxsw_sp2_acl_tcam_entry *entry = entry_priv;
180
181         entry->act_block = rulei->act_block;
182         return mlxsw_sp_acl_ctcam_entry_add(mlxsw_sp, &region->cregion,
183                                             &chunk->cchunk, &entry->centry,
184                                             rulei, true);
185 }
186
187 static void mlxsw_sp2_acl_tcam_entry_del(struct mlxsw_sp *mlxsw_sp,
188                                          void *region_priv, void *chunk_priv,
189                                          void *entry_priv)
190 {
191         struct mlxsw_sp2_acl_tcam_region *region = region_priv;
192         struct mlxsw_sp2_acl_tcam_chunk *chunk = chunk_priv;
193         struct mlxsw_sp2_acl_tcam_entry *entry = entry_priv;
194
195         mlxsw_sp_acl_ctcam_entry_del(mlxsw_sp, &region->cregion,
196                                      &chunk->cchunk, &entry->centry);
197 }
198
199 static int
200 mlxsw_sp2_acl_tcam_entry_activity_get(struct mlxsw_sp *mlxsw_sp,
201                                       void *region_priv, void *entry_priv,
202                                       bool *activity)
203 {
204         struct mlxsw_sp2_acl_tcam_entry *entry = entry_priv;
205
206         return mlxsw_afa_block_activity_get(entry->act_block, activity);
207 }
208
209 const struct mlxsw_sp_acl_tcam_ops mlxsw_sp2_acl_tcam_ops = {
210         .key_type               = MLXSW_REG_PTAR_KEY_TYPE_FLEX2,
211         .priv_size              = sizeof(struct mlxsw_sp2_acl_tcam),
212         .init                   = mlxsw_sp2_acl_tcam_init,
213         .fini                   = mlxsw_sp2_acl_tcam_fini,
214         .region_priv_size       = sizeof(struct mlxsw_sp2_acl_tcam_region),
215         .region_init            = mlxsw_sp2_acl_tcam_region_init,
216         .region_fini            = mlxsw_sp2_acl_tcam_region_fini,
217         .region_associate       = mlxsw_sp2_acl_tcam_region_associate,
218         .chunk_priv_size        = sizeof(struct mlxsw_sp2_acl_tcam_chunk),
219         .chunk_init             = mlxsw_sp2_acl_tcam_chunk_init,
220         .chunk_fini             = mlxsw_sp2_acl_tcam_chunk_fini,
221         .entry_priv_size        = sizeof(struct mlxsw_sp2_acl_tcam_entry),
222         .entry_add              = mlxsw_sp2_acl_tcam_entry_add,
223         .entry_del              = mlxsw_sp2_acl_tcam_entry_del,
224         .entry_activity_get     = mlxsw_sp2_acl_tcam_entry_activity_get,
225 };