1*4882a593Smuzhiyun // SPDX-License-Identifier: (GPL-2.0 OR MIT)
2*4882a593Smuzhiyun /* Microsemi Ocelot Switch driver
3*4882a593Smuzhiyun * Copyright (c) 2019 Microsemi Corporation
4*4882a593Smuzhiyun */
5*4882a593Smuzhiyun
6*4882a593Smuzhiyun #include <linux/iopoll.h>
7*4882a593Smuzhiyun #include <linux/proc_fs.h>
8*4882a593Smuzhiyun
9*4882a593Smuzhiyun #include <soc/mscc/ocelot_vcap.h>
10*4882a593Smuzhiyun #include "ocelot_police.h"
11*4882a593Smuzhiyun #include "ocelot_vcap.h"
12*4882a593Smuzhiyun
13*4882a593Smuzhiyun #define ENTRY_WIDTH 32
14*4882a593Smuzhiyun
15*4882a593Smuzhiyun enum vcap_sel {
16*4882a593Smuzhiyun VCAP_SEL_ENTRY = 0x1,
17*4882a593Smuzhiyun VCAP_SEL_ACTION = 0x2,
18*4882a593Smuzhiyun VCAP_SEL_COUNTER = 0x4,
19*4882a593Smuzhiyun VCAP_SEL_ALL = 0x7,
20*4882a593Smuzhiyun };
21*4882a593Smuzhiyun
22*4882a593Smuzhiyun enum vcap_cmd {
23*4882a593Smuzhiyun VCAP_CMD_WRITE = 0, /* Copy from Cache to TCAM */
24*4882a593Smuzhiyun VCAP_CMD_READ = 1, /* Copy from TCAM to Cache */
25*4882a593Smuzhiyun VCAP_CMD_MOVE_UP = 2, /* Move <count> up */
26*4882a593Smuzhiyun VCAP_CMD_MOVE_DOWN = 3, /* Move <count> down */
27*4882a593Smuzhiyun VCAP_CMD_INITIALIZE = 4, /* Write all (from cache) */
28*4882a593Smuzhiyun };
29*4882a593Smuzhiyun
30*4882a593Smuzhiyun #define VCAP_ENTRY_WIDTH 12 /* Max entry width (32bit words) */
31*4882a593Smuzhiyun #define VCAP_COUNTER_WIDTH 4 /* Max counter width (32bit words) */
32*4882a593Smuzhiyun
33*4882a593Smuzhiyun struct vcap_data {
34*4882a593Smuzhiyun u32 entry[VCAP_ENTRY_WIDTH]; /* ENTRY_DAT */
35*4882a593Smuzhiyun u32 mask[VCAP_ENTRY_WIDTH]; /* MASK_DAT */
36*4882a593Smuzhiyun u32 action[VCAP_ENTRY_WIDTH]; /* ACTION_DAT */
37*4882a593Smuzhiyun u32 counter[VCAP_COUNTER_WIDTH]; /* CNT_DAT */
38*4882a593Smuzhiyun u32 tg; /* TG_DAT */
39*4882a593Smuzhiyun u32 type; /* Action type */
40*4882a593Smuzhiyun u32 tg_sw; /* Current type-group */
41*4882a593Smuzhiyun u32 cnt; /* Current counter */
42*4882a593Smuzhiyun u32 key_offset; /* Current entry offset */
43*4882a593Smuzhiyun u32 action_offset; /* Current action offset */
44*4882a593Smuzhiyun u32 counter_offset; /* Current counter offset */
45*4882a593Smuzhiyun u32 tg_value; /* Current type-group value */
46*4882a593Smuzhiyun u32 tg_mask; /* Current type-group mask */
47*4882a593Smuzhiyun };
48*4882a593Smuzhiyun
vcap_read_update_ctrl(struct ocelot * ocelot,const struct vcap_props * vcap)49*4882a593Smuzhiyun static u32 vcap_read_update_ctrl(struct ocelot *ocelot,
50*4882a593Smuzhiyun const struct vcap_props *vcap)
51*4882a593Smuzhiyun {
52*4882a593Smuzhiyun return ocelot_target_read(ocelot, vcap->target, VCAP_CORE_UPDATE_CTRL);
53*4882a593Smuzhiyun }
54*4882a593Smuzhiyun
vcap_cmd(struct ocelot * ocelot,const struct vcap_props * vcap,u16 ix,int cmd,int sel)55*4882a593Smuzhiyun static void vcap_cmd(struct ocelot *ocelot, const struct vcap_props *vcap,
56*4882a593Smuzhiyun u16 ix, int cmd, int sel)
57*4882a593Smuzhiyun {
58*4882a593Smuzhiyun u32 value = (VCAP_CORE_UPDATE_CTRL_UPDATE_CMD(cmd) |
59*4882a593Smuzhiyun VCAP_CORE_UPDATE_CTRL_UPDATE_ADDR(ix) |
60*4882a593Smuzhiyun VCAP_CORE_UPDATE_CTRL_UPDATE_SHOT);
61*4882a593Smuzhiyun
62*4882a593Smuzhiyun if ((sel & VCAP_SEL_ENTRY) && ix >= vcap->entry_count)
63*4882a593Smuzhiyun return;
64*4882a593Smuzhiyun
65*4882a593Smuzhiyun if (!(sel & VCAP_SEL_ENTRY))
66*4882a593Smuzhiyun value |= VCAP_CORE_UPDATE_CTRL_UPDATE_ENTRY_DIS;
67*4882a593Smuzhiyun
68*4882a593Smuzhiyun if (!(sel & VCAP_SEL_ACTION))
69*4882a593Smuzhiyun value |= VCAP_CORE_UPDATE_CTRL_UPDATE_ACTION_DIS;
70*4882a593Smuzhiyun
71*4882a593Smuzhiyun if (!(sel & VCAP_SEL_COUNTER))
72*4882a593Smuzhiyun value |= VCAP_CORE_UPDATE_CTRL_UPDATE_CNT_DIS;
73*4882a593Smuzhiyun
74*4882a593Smuzhiyun ocelot_target_write(ocelot, vcap->target, value, VCAP_CORE_UPDATE_CTRL);
75*4882a593Smuzhiyun
76*4882a593Smuzhiyun read_poll_timeout(vcap_read_update_ctrl, value,
77*4882a593Smuzhiyun (value & VCAP_CORE_UPDATE_CTRL_UPDATE_SHOT) == 0,
78*4882a593Smuzhiyun 10, 100000, false, ocelot, vcap);
79*4882a593Smuzhiyun }
80*4882a593Smuzhiyun
81*4882a593Smuzhiyun /* Convert from 0-based row to VCAP entry row and run command */
vcap_row_cmd(struct ocelot * ocelot,const struct vcap_props * vcap,u32 row,int cmd,int sel)82*4882a593Smuzhiyun static void vcap_row_cmd(struct ocelot *ocelot, const struct vcap_props *vcap,
83*4882a593Smuzhiyun u32 row, int cmd, int sel)
84*4882a593Smuzhiyun {
85*4882a593Smuzhiyun vcap_cmd(ocelot, vcap, vcap->entry_count - row - 1, cmd, sel);
86*4882a593Smuzhiyun }
87*4882a593Smuzhiyun
vcap_entry2cache(struct ocelot * ocelot,const struct vcap_props * vcap,struct vcap_data * data)88*4882a593Smuzhiyun static void vcap_entry2cache(struct ocelot *ocelot,
89*4882a593Smuzhiyun const struct vcap_props *vcap,
90*4882a593Smuzhiyun struct vcap_data *data)
91*4882a593Smuzhiyun {
92*4882a593Smuzhiyun u32 entry_words, i;
93*4882a593Smuzhiyun
94*4882a593Smuzhiyun entry_words = DIV_ROUND_UP(vcap->entry_width, ENTRY_WIDTH);
95*4882a593Smuzhiyun
96*4882a593Smuzhiyun for (i = 0; i < entry_words; i++) {
97*4882a593Smuzhiyun ocelot_target_write_rix(ocelot, vcap->target, data->entry[i],
98*4882a593Smuzhiyun VCAP_CACHE_ENTRY_DAT, i);
99*4882a593Smuzhiyun ocelot_target_write_rix(ocelot, vcap->target, ~data->mask[i],
100*4882a593Smuzhiyun VCAP_CACHE_MASK_DAT, i);
101*4882a593Smuzhiyun }
102*4882a593Smuzhiyun ocelot_target_write(ocelot, vcap->target, data->tg, VCAP_CACHE_TG_DAT);
103*4882a593Smuzhiyun }
104*4882a593Smuzhiyun
vcap_cache2entry(struct ocelot * ocelot,const struct vcap_props * vcap,struct vcap_data * data)105*4882a593Smuzhiyun static void vcap_cache2entry(struct ocelot *ocelot,
106*4882a593Smuzhiyun const struct vcap_props *vcap,
107*4882a593Smuzhiyun struct vcap_data *data)
108*4882a593Smuzhiyun {
109*4882a593Smuzhiyun u32 entry_words, i;
110*4882a593Smuzhiyun
111*4882a593Smuzhiyun entry_words = DIV_ROUND_UP(vcap->entry_width, ENTRY_WIDTH);
112*4882a593Smuzhiyun
113*4882a593Smuzhiyun for (i = 0; i < entry_words; i++) {
114*4882a593Smuzhiyun data->entry[i] = ocelot_target_read_rix(ocelot, vcap->target,
115*4882a593Smuzhiyun VCAP_CACHE_ENTRY_DAT, i);
116*4882a593Smuzhiyun // Invert mask
117*4882a593Smuzhiyun data->mask[i] = ~ocelot_target_read_rix(ocelot, vcap->target,
118*4882a593Smuzhiyun VCAP_CACHE_MASK_DAT, i);
119*4882a593Smuzhiyun }
120*4882a593Smuzhiyun data->tg = ocelot_target_read(ocelot, vcap->target, VCAP_CACHE_TG_DAT);
121*4882a593Smuzhiyun }
122*4882a593Smuzhiyun
vcap_action2cache(struct ocelot * ocelot,const struct vcap_props * vcap,struct vcap_data * data)123*4882a593Smuzhiyun static void vcap_action2cache(struct ocelot *ocelot,
124*4882a593Smuzhiyun const struct vcap_props *vcap,
125*4882a593Smuzhiyun struct vcap_data *data)
126*4882a593Smuzhiyun {
127*4882a593Smuzhiyun u32 action_words, mask;
128*4882a593Smuzhiyun int i, width;
129*4882a593Smuzhiyun
130*4882a593Smuzhiyun /* Encode action type */
131*4882a593Smuzhiyun width = vcap->action_type_width;
132*4882a593Smuzhiyun if (width) {
133*4882a593Smuzhiyun mask = GENMASK(width, 0);
134*4882a593Smuzhiyun data->action[0] = ((data->action[0] & ~mask) | data->type);
135*4882a593Smuzhiyun }
136*4882a593Smuzhiyun
137*4882a593Smuzhiyun action_words = DIV_ROUND_UP(vcap->action_width, ENTRY_WIDTH);
138*4882a593Smuzhiyun
139*4882a593Smuzhiyun for (i = 0; i < action_words; i++)
140*4882a593Smuzhiyun ocelot_target_write_rix(ocelot, vcap->target, data->action[i],
141*4882a593Smuzhiyun VCAP_CACHE_ACTION_DAT, i);
142*4882a593Smuzhiyun
143*4882a593Smuzhiyun for (i = 0; i < vcap->counter_words; i++)
144*4882a593Smuzhiyun ocelot_target_write_rix(ocelot, vcap->target, data->counter[i],
145*4882a593Smuzhiyun VCAP_CACHE_CNT_DAT, i);
146*4882a593Smuzhiyun }
147*4882a593Smuzhiyun
vcap_cache2action(struct ocelot * ocelot,const struct vcap_props * vcap,struct vcap_data * data)148*4882a593Smuzhiyun static void vcap_cache2action(struct ocelot *ocelot,
149*4882a593Smuzhiyun const struct vcap_props *vcap,
150*4882a593Smuzhiyun struct vcap_data *data)
151*4882a593Smuzhiyun {
152*4882a593Smuzhiyun u32 action_words;
153*4882a593Smuzhiyun int i, width;
154*4882a593Smuzhiyun
155*4882a593Smuzhiyun action_words = DIV_ROUND_UP(vcap->action_width, ENTRY_WIDTH);
156*4882a593Smuzhiyun
157*4882a593Smuzhiyun for (i = 0; i < action_words; i++)
158*4882a593Smuzhiyun data->action[i] = ocelot_target_read_rix(ocelot, vcap->target,
159*4882a593Smuzhiyun VCAP_CACHE_ACTION_DAT,
160*4882a593Smuzhiyun i);
161*4882a593Smuzhiyun
162*4882a593Smuzhiyun for (i = 0; i < vcap->counter_words; i++)
163*4882a593Smuzhiyun data->counter[i] = ocelot_target_read_rix(ocelot, vcap->target,
164*4882a593Smuzhiyun VCAP_CACHE_CNT_DAT,
165*4882a593Smuzhiyun i);
166*4882a593Smuzhiyun
167*4882a593Smuzhiyun /* Extract action type */
168*4882a593Smuzhiyun width = vcap->action_type_width;
169*4882a593Smuzhiyun data->type = (width ? (data->action[0] & GENMASK(width, 0)) : 0);
170*4882a593Smuzhiyun }
171*4882a593Smuzhiyun
172*4882a593Smuzhiyun /* Calculate offsets for entry */
vcap_data_offset_get(const struct vcap_props * vcap,struct vcap_data * data,int ix)173*4882a593Smuzhiyun static void vcap_data_offset_get(const struct vcap_props *vcap,
174*4882a593Smuzhiyun struct vcap_data *data, int ix)
175*4882a593Smuzhiyun {
176*4882a593Smuzhiyun int num_subwords_per_entry, num_subwords_per_action;
177*4882a593Smuzhiyun int i, col, offset, num_entries_per_row, base;
178*4882a593Smuzhiyun u32 width = vcap->tg_width;
179*4882a593Smuzhiyun
180*4882a593Smuzhiyun switch (data->tg_sw) {
181*4882a593Smuzhiyun case VCAP_TG_FULL:
182*4882a593Smuzhiyun num_entries_per_row = 1;
183*4882a593Smuzhiyun break;
184*4882a593Smuzhiyun case VCAP_TG_HALF:
185*4882a593Smuzhiyun num_entries_per_row = 2;
186*4882a593Smuzhiyun break;
187*4882a593Smuzhiyun case VCAP_TG_QUARTER:
188*4882a593Smuzhiyun num_entries_per_row = 4;
189*4882a593Smuzhiyun break;
190*4882a593Smuzhiyun default:
191*4882a593Smuzhiyun return;
192*4882a593Smuzhiyun }
193*4882a593Smuzhiyun
194*4882a593Smuzhiyun col = (ix % num_entries_per_row);
195*4882a593Smuzhiyun num_subwords_per_entry = (vcap->sw_count / num_entries_per_row);
196*4882a593Smuzhiyun base = (vcap->sw_count - col * num_subwords_per_entry -
197*4882a593Smuzhiyun num_subwords_per_entry);
198*4882a593Smuzhiyun data->tg_value = 0;
199*4882a593Smuzhiyun data->tg_mask = 0;
200*4882a593Smuzhiyun for (i = 0; i < num_subwords_per_entry; i++) {
201*4882a593Smuzhiyun offset = ((base + i) * width);
202*4882a593Smuzhiyun data->tg_value |= (data->tg_sw << offset);
203*4882a593Smuzhiyun data->tg_mask |= GENMASK(offset + width - 1, offset);
204*4882a593Smuzhiyun }
205*4882a593Smuzhiyun
206*4882a593Smuzhiyun /* Calculate key/action/counter offsets */
207*4882a593Smuzhiyun col = (num_entries_per_row - col - 1);
208*4882a593Smuzhiyun data->key_offset = (base * vcap->entry_width) / vcap->sw_count;
209*4882a593Smuzhiyun data->counter_offset = (num_subwords_per_entry * col *
210*4882a593Smuzhiyun vcap->counter_width);
211*4882a593Smuzhiyun i = data->type;
212*4882a593Smuzhiyun width = vcap->action_table[i].width;
213*4882a593Smuzhiyun num_subwords_per_action = vcap->action_table[i].count;
214*4882a593Smuzhiyun data->action_offset = ((num_subwords_per_action * col * width) /
215*4882a593Smuzhiyun num_entries_per_row);
216*4882a593Smuzhiyun data->action_offset += vcap->action_type_width;
217*4882a593Smuzhiyun }
218*4882a593Smuzhiyun
vcap_data_set(u32 * data,u32 offset,u32 len,u32 value)219*4882a593Smuzhiyun static void vcap_data_set(u32 *data, u32 offset, u32 len, u32 value)
220*4882a593Smuzhiyun {
221*4882a593Smuzhiyun u32 i, v, m;
222*4882a593Smuzhiyun
223*4882a593Smuzhiyun for (i = 0; i < len; i++, offset++) {
224*4882a593Smuzhiyun v = data[offset / ENTRY_WIDTH];
225*4882a593Smuzhiyun m = (1 << (offset % ENTRY_WIDTH));
226*4882a593Smuzhiyun if (value & (1 << i))
227*4882a593Smuzhiyun v |= m;
228*4882a593Smuzhiyun else
229*4882a593Smuzhiyun v &= ~m;
230*4882a593Smuzhiyun data[offset / ENTRY_WIDTH] = v;
231*4882a593Smuzhiyun }
232*4882a593Smuzhiyun }
233*4882a593Smuzhiyun
vcap_data_get(u32 * data,u32 offset,u32 len)234*4882a593Smuzhiyun static u32 vcap_data_get(u32 *data, u32 offset, u32 len)
235*4882a593Smuzhiyun {
236*4882a593Smuzhiyun u32 i, v, m, value = 0;
237*4882a593Smuzhiyun
238*4882a593Smuzhiyun for (i = 0; i < len; i++, offset++) {
239*4882a593Smuzhiyun v = data[offset / ENTRY_WIDTH];
240*4882a593Smuzhiyun m = (1 << (offset % ENTRY_WIDTH));
241*4882a593Smuzhiyun if (v & m)
242*4882a593Smuzhiyun value |= (1 << i);
243*4882a593Smuzhiyun }
244*4882a593Smuzhiyun return value;
245*4882a593Smuzhiyun }
246*4882a593Smuzhiyun
vcap_key_field_set(struct vcap_data * data,u32 offset,u32 width,u32 value,u32 mask)247*4882a593Smuzhiyun static void vcap_key_field_set(struct vcap_data *data, u32 offset, u32 width,
248*4882a593Smuzhiyun u32 value, u32 mask)
249*4882a593Smuzhiyun {
250*4882a593Smuzhiyun vcap_data_set(data->entry, offset + data->key_offset, width, value);
251*4882a593Smuzhiyun vcap_data_set(data->mask, offset + data->key_offset, width, mask);
252*4882a593Smuzhiyun }
253*4882a593Smuzhiyun
vcap_key_set(const struct vcap_props * vcap,struct vcap_data * data,int field,u32 value,u32 mask)254*4882a593Smuzhiyun static void vcap_key_set(const struct vcap_props *vcap, struct vcap_data *data,
255*4882a593Smuzhiyun int field, u32 value, u32 mask)
256*4882a593Smuzhiyun {
257*4882a593Smuzhiyun u32 offset = vcap->keys[field].offset;
258*4882a593Smuzhiyun u32 length = vcap->keys[field].length;
259*4882a593Smuzhiyun
260*4882a593Smuzhiyun vcap_key_field_set(data, offset, length, value, mask);
261*4882a593Smuzhiyun }
262*4882a593Smuzhiyun
vcap_key_bytes_set(const struct vcap_props * vcap,struct vcap_data * data,int field,u8 * val,u8 * msk)263*4882a593Smuzhiyun static void vcap_key_bytes_set(const struct vcap_props *vcap,
264*4882a593Smuzhiyun struct vcap_data *data, int field,
265*4882a593Smuzhiyun u8 *val, u8 *msk)
266*4882a593Smuzhiyun {
267*4882a593Smuzhiyun u32 offset = vcap->keys[field].offset;
268*4882a593Smuzhiyun u32 count = vcap->keys[field].length;
269*4882a593Smuzhiyun u32 i, j, n = 0, value = 0, mask = 0;
270*4882a593Smuzhiyun
271*4882a593Smuzhiyun WARN_ON(count % 8);
272*4882a593Smuzhiyun
273*4882a593Smuzhiyun /* Data wider than 32 bits are split up in chunks of maximum 32 bits.
274*4882a593Smuzhiyun * The 32 LSB of the data are written to the 32 MSB of the TCAM.
275*4882a593Smuzhiyun */
276*4882a593Smuzhiyun offset += count;
277*4882a593Smuzhiyun count /= 8;
278*4882a593Smuzhiyun
279*4882a593Smuzhiyun for (i = 0; i < count; i++) {
280*4882a593Smuzhiyun j = (count - i - 1);
281*4882a593Smuzhiyun value += (val[j] << n);
282*4882a593Smuzhiyun mask += (msk[j] << n);
283*4882a593Smuzhiyun n += 8;
284*4882a593Smuzhiyun if (n == ENTRY_WIDTH || (i + 1) == count) {
285*4882a593Smuzhiyun offset -= n;
286*4882a593Smuzhiyun vcap_key_field_set(data, offset, n, value, mask);
287*4882a593Smuzhiyun n = 0;
288*4882a593Smuzhiyun value = 0;
289*4882a593Smuzhiyun mask = 0;
290*4882a593Smuzhiyun }
291*4882a593Smuzhiyun }
292*4882a593Smuzhiyun }
293*4882a593Smuzhiyun
vcap_key_l4_port_set(const struct vcap_props * vcap,struct vcap_data * data,int field,struct ocelot_vcap_udp_tcp * port)294*4882a593Smuzhiyun static void vcap_key_l4_port_set(const struct vcap_props *vcap,
295*4882a593Smuzhiyun struct vcap_data *data, int field,
296*4882a593Smuzhiyun struct ocelot_vcap_udp_tcp *port)
297*4882a593Smuzhiyun {
298*4882a593Smuzhiyun u32 offset = vcap->keys[field].offset;
299*4882a593Smuzhiyun u32 length = vcap->keys[field].length;
300*4882a593Smuzhiyun
301*4882a593Smuzhiyun WARN_ON(length != 16);
302*4882a593Smuzhiyun
303*4882a593Smuzhiyun vcap_key_field_set(data, offset, length, port->value, port->mask);
304*4882a593Smuzhiyun }
305*4882a593Smuzhiyun
vcap_key_bit_set(const struct vcap_props * vcap,struct vcap_data * data,int field,enum ocelot_vcap_bit val)306*4882a593Smuzhiyun static void vcap_key_bit_set(const struct vcap_props *vcap,
307*4882a593Smuzhiyun struct vcap_data *data, int field,
308*4882a593Smuzhiyun enum ocelot_vcap_bit val)
309*4882a593Smuzhiyun {
310*4882a593Smuzhiyun u32 value = (val == OCELOT_VCAP_BIT_1 ? 1 : 0);
311*4882a593Smuzhiyun u32 msk = (val == OCELOT_VCAP_BIT_ANY ? 0 : 1);
312*4882a593Smuzhiyun u32 offset = vcap->keys[field].offset;
313*4882a593Smuzhiyun u32 length = vcap->keys[field].length;
314*4882a593Smuzhiyun
315*4882a593Smuzhiyun WARN_ON(length != 1);
316*4882a593Smuzhiyun
317*4882a593Smuzhiyun vcap_key_field_set(data, offset, length, value, msk);
318*4882a593Smuzhiyun }
319*4882a593Smuzhiyun
vcap_action_set(const struct vcap_props * vcap,struct vcap_data * data,int field,u32 value)320*4882a593Smuzhiyun static void vcap_action_set(const struct vcap_props *vcap,
321*4882a593Smuzhiyun struct vcap_data *data, int field, u32 value)
322*4882a593Smuzhiyun {
323*4882a593Smuzhiyun int offset = vcap->actions[field].offset;
324*4882a593Smuzhiyun int length = vcap->actions[field].length;
325*4882a593Smuzhiyun
326*4882a593Smuzhiyun vcap_data_set(data->action, offset + data->action_offset, length,
327*4882a593Smuzhiyun value);
328*4882a593Smuzhiyun }
329*4882a593Smuzhiyun
is2_action_set(struct ocelot * ocelot,struct vcap_data * data,struct ocelot_vcap_filter * filter)330*4882a593Smuzhiyun static void is2_action_set(struct ocelot *ocelot, struct vcap_data *data,
331*4882a593Smuzhiyun struct ocelot_vcap_filter *filter)
332*4882a593Smuzhiyun {
333*4882a593Smuzhiyun const struct vcap_props *vcap = &ocelot->vcap[VCAP_IS2];
334*4882a593Smuzhiyun struct ocelot_vcap_action *a = &filter->action;
335*4882a593Smuzhiyun
336*4882a593Smuzhiyun vcap_action_set(vcap, data, VCAP_IS2_ACT_MASK_MODE, a->mask_mode);
337*4882a593Smuzhiyun vcap_action_set(vcap, data, VCAP_IS2_ACT_PORT_MASK, a->port_mask);
338*4882a593Smuzhiyun vcap_action_set(vcap, data, VCAP_IS2_ACT_POLICE_ENA, a->police_ena);
339*4882a593Smuzhiyun vcap_action_set(vcap, data, VCAP_IS2_ACT_POLICE_IDX, a->pol_ix);
340*4882a593Smuzhiyun vcap_action_set(vcap, data, VCAP_IS2_ACT_CPU_QU_NUM, a->cpu_qu_num);
341*4882a593Smuzhiyun vcap_action_set(vcap, data, VCAP_IS2_ACT_CPU_COPY_ENA, a->cpu_copy_ena);
342*4882a593Smuzhiyun }
343*4882a593Smuzhiyun
is2_entry_set(struct ocelot * ocelot,int ix,struct ocelot_vcap_filter * filter)344*4882a593Smuzhiyun static void is2_entry_set(struct ocelot *ocelot, int ix,
345*4882a593Smuzhiyun struct ocelot_vcap_filter *filter)
346*4882a593Smuzhiyun {
347*4882a593Smuzhiyun const struct vcap_props *vcap = &ocelot->vcap[VCAP_IS2];
348*4882a593Smuzhiyun struct ocelot_vcap_key_vlan *tag = &filter->vlan;
349*4882a593Smuzhiyun u32 val, msk, type, type_mask = 0xf, i, count;
350*4882a593Smuzhiyun struct ocelot_vcap_u64 payload;
351*4882a593Smuzhiyun struct vcap_data data;
352*4882a593Smuzhiyun int row = (ix / 2);
353*4882a593Smuzhiyun
354*4882a593Smuzhiyun memset(&payload, 0, sizeof(payload));
355*4882a593Smuzhiyun memset(&data, 0, sizeof(data));
356*4882a593Smuzhiyun
357*4882a593Smuzhiyun /* Read row */
358*4882a593Smuzhiyun vcap_row_cmd(ocelot, vcap, row, VCAP_CMD_READ, VCAP_SEL_ALL);
359*4882a593Smuzhiyun vcap_cache2entry(ocelot, vcap, &data);
360*4882a593Smuzhiyun vcap_cache2action(ocelot, vcap, &data);
361*4882a593Smuzhiyun
362*4882a593Smuzhiyun data.tg_sw = VCAP_TG_HALF;
363*4882a593Smuzhiyun vcap_data_offset_get(vcap, &data, ix);
364*4882a593Smuzhiyun data.tg = (data.tg & ~data.tg_mask);
365*4882a593Smuzhiyun if (filter->prio != 0)
366*4882a593Smuzhiyun data.tg |= data.tg_value;
367*4882a593Smuzhiyun
368*4882a593Smuzhiyun data.type = IS2_ACTION_TYPE_NORMAL;
369*4882a593Smuzhiyun
370*4882a593Smuzhiyun vcap_key_set(vcap, &data, VCAP_IS2_HK_PAG, filter->pag, 0xff);
371*4882a593Smuzhiyun vcap_key_bit_set(vcap, &data, VCAP_IS2_HK_FIRST,
372*4882a593Smuzhiyun (filter->lookup == 0) ? OCELOT_VCAP_BIT_1 :
373*4882a593Smuzhiyun OCELOT_VCAP_BIT_0);
374*4882a593Smuzhiyun vcap_key_set(vcap, &data, VCAP_IS2_HK_IGR_PORT_MASK, 0,
375*4882a593Smuzhiyun ~filter->ingress_port_mask);
376*4882a593Smuzhiyun vcap_key_bit_set(vcap, &data, VCAP_IS2_HK_HOST_MATCH,
377*4882a593Smuzhiyun OCELOT_VCAP_BIT_ANY);
378*4882a593Smuzhiyun vcap_key_bit_set(vcap, &data, VCAP_IS2_HK_L2_MC, filter->dmac_mc);
379*4882a593Smuzhiyun vcap_key_bit_set(vcap, &data, VCAP_IS2_HK_L2_BC, filter->dmac_bc);
380*4882a593Smuzhiyun vcap_key_bit_set(vcap, &data, VCAP_IS2_HK_VLAN_TAGGED, tag->tagged);
381*4882a593Smuzhiyun vcap_key_set(vcap, &data, VCAP_IS2_HK_VID,
382*4882a593Smuzhiyun tag->vid.value, tag->vid.mask);
383*4882a593Smuzhiyun vcap_key_set(vcap, &data, VCAP_IS2_HK_PCP,
384*4882a593Smuzhiyun tag->pcp.value[0], tag->pcp.mask[0]);
385*4882a593Smuzhiyun vcap_key_bit_set(vcap, &data, VCAP_IS2_HK_DEI, tag->dei);
386*4882a593Smuzhiyun
387*4882a593Smuzhiyun switch (filter->key_type) {
388*4882a593Smuzhiyun case OCELOT_VCAP_KEY_ETYPE: {
389*4882a593Smuzhiyun struct ocelot_vcap_key_etype *etype = &filter->key.etype;
390*4882a593Smuzhiyun
391*4882a593Smuzhiyun type = IS2_TYPE_ETYPE;
392*4882a593Smuzhiyun vcap_key_bytes_set(vcap, &data, VCAP_IS2_HK_L2_DMAC,
393*4882a593Smuzhiyun etype->dmac.value, etype->dmac.mask);
394*4882a593Smuzhiyun vcap_key_bytes_set(vcap, &data, VCAP_IS2_HK_L2_SMAC,
395*4882a593Smuzhiyun etype->smac.value, etype->smac.mask);
396*4882a593Smuzhiyun vcap_key_bytes_set(vcap, &data, VCAP_IS2_HK_MAC_ETYPE_ETYPE,
397*4882a593Smuzhiyun etype->etype.value, etype->etype.mask);
398*4882a593Smuzhiyun /* Clear unused bits */
399*4882a593Smuzhiyun vcap_key_set(vcap, &data, VCAP_IS2_HK_MAC_ETYPE_L2_PAYLOAD0,
400*4882a593Smuzhiyun 0, 0);
401*4882a593Smuzhiyun vcap_key_set(vcap, &data, VCAP_IS2_HK_MAC_ETYPE_L2_PAYLOAD1,
402*4882a593Smuzhiyun 0, 0);
403*4882a593Smuzhiyun vcap_key_set(vcap, &data, VCAP_IS2_HK_MAC_ETYPE_L2_PAYLOAD2,
404*4882a593Smuzhiyun 0, 0);
405*4882a593Smuzhiyun vcap_key_bytes_set(vcap, &data,
406*4882a593Smuzhiyun VCAP_IS2_HK_MAC_ETYPE_L2_PAYLOAD0,
407*4882a593Smuzhiyun etype->data.value, etype->data.mask);
408*4882a593Smuzhiyun break;
409*4882a593Smuzhiyun }
410*4882a593Smuzhiyun case OCELOT_VCAP_KEY_LLC: {
411*4882a593Smuzhiyun struct ocelot_vcap_key_llc *llc = &filter->key.llc;
412*4882a593Smuzhiyun
413*4882a593Smuzhiyun type = IS2_TYPE_LLC;
414*4882a593Smuzhiyun vcap_key_bytes_set(vcap, &data, VCAP_IS2_HK_L2_DMAC,
415*4882a593Smuzhiyun llc->dmac.value, llc->dmac.mask);
416*4882a593Smuzhiyun vcap_key_bytes_set(vcap, &data, VCAP_IS2_HK_L2_SMAC,
417*4882a593Smuzhiyun llc->smac.value, llc->smac.mask);
418*4882a593Smuzhiyun for (i = 0; i < 4; i++) {
419*4882a593Smuzhiyun payload.value[i] = llc->llc.value[i];
420*4882a593Smuzhiyun payload.mask[i] = llc->llc.mask[i];
421*4882a593Smuzhiyun }
422*4882a593Smuzhiyun vcap_key_bytes_set(vcap, &data, VCAP_IS2_HK_MAC_LLC_L2_LLC,
423*4882a593Smuzhiyun payload.value, payload.mask);
424*4882a593Smuzhiyun break;
425*4882a593Smuzhiyun }
426*4882a593Smuzhiyun case OCELOT_VCAP_KEY_SNAP: {
427*4882a593Smuzhiyun struct ocelot_vcap_key_snap *snap = &filter->key.snap;
428*4882a593Smuzhiyun
429*4882a593Smuzhiyun type = IS2_TYPE_SNAP;
430*4882a593Smuzhiyun vcap_key_bytes_set(vcap, &data, VCAP_IS2_HK_L2_DMAC,
431*4882a593Smuzhiyun snap->dmac.value, snap->dmac.mask);
432*4882a593Smuzhiyun vcap_key_bytes_set(vcap, &data, VCAP_IS2_HK_L2_SMAC,
433*4882a593Smuzhiyun snap->smac.value, snap->smac.mask);
434*4882a593Smuzhiyun vcap_key_bytes_set(vcap, &data, VCAP_IS2_HK_MAC_SNAP_L2_SNAP,
435*4882a593Smuzhiyun filter->key.snap.snap.value,
436*4882a593Smuzhiyun filter->key.snap.snap.mask);
437*4882a593Smuzhiyun break;
438*4882a593Smuzhiyun }
439*4882a593Smuzhiyun case OCELOT_VCAP_KEY_ARP: {
440*4882a593Smuzhiyun struct ocelot_vcap_key_arp *arp = &filter->key.arp;
441*4882a593Smuzhiyun
442*4882a593Smuzhiyun type = IS2_TYPE_ARP;
443*4882a593Smuzhiyun vcap_key_bytes_set(vcap, &data, VCAP_IS2_HK_MAC_ARP_SMAC,
444*4882a593Smuzhiyun arp->smac.value, arp->smac.mask);
445*4882a593Smuzhiyun vcap_key_bit_set(vcap, &data,
446*4882a593Smuzhiyun VCAP_IS2_HK_MAC_ARP_ADDR_SPACE_OK,
447*4882a593Smuzhiyun arp->ethernet);
448*4882a593Smuzhiyun vcap_key_bit_set(vcap, &data,
449*4882a593Smuzhiyun VCAP_IS2_HK_MAC_ARP_PROTO_SPACE_OK,
450*4882a593Smuzhiyun arp->ip);
451*4882a593Smuzhiyun vcap_key_bit_set(vcap, &data,
452*4882a593Smuzhiyun VCAP_IS2_HK_MAC_ARP_LEN_OK,
453*4882a593Smuzhiyun arp->length);
454*4882a593Smuzhiyun vcap_key_bit_set(vcap, &data,
455*4882a593Smuzhiyun VCAP_IS2_HK_MAC_ARP_TARGET_MATCH,
456*4882a593Smuzhiyun arp->dmac_match);
457*4882a593Smuzhiyun vcap_key_bit_set(vcap, &data,
458*4882a593Smuzhiyun VCAP_IS2_HK_MAC_ARP_SENDER_MATCH,
459*4882a593Smuzhiyun arp->smac_match);
460*4882a593Smuzhiyun vcap_key_bit_set(vcap, &data,
461*4882a593Smuzhiyun VCAP_IS2_HK_MAC_ARP_OPCODE_UNKNOWN,
462*4882a593Smuzhiyun arp->unknown);
463*4882a593Smuzhiyun
464*4882a593Smuzhiyun /* OPCODE is inverse, bit 0 is reply flag, bit 1 is RARP flag */
465*4882a593Smuzhiyun val = ((arp->req == OCELOT_VCAP_BIT_0 ? 1 : 0) |
466*4882a593Smuzhiyun (arp->arp == OCELOT_VCAP_BIT_0 ? 2 : 0));
467*4882a593Smuzhiyun msk = ((arp->req == OCELOT_VCAP_BIT_ANY ? 0 : 1) |
468*4882a593Smuzhiyun (arp->arp == OCELOT_VCAP_BIT_ANY ? 0 : 2));
469*4882a593Smuzhiyun vcap_key_set(vcap, &data, VCAP_IS2_HK_MAC_ARP_OPCODE,
470*4882a593Smuzhiyun val, msk);
471*4882a593Smuzhiyun vcap_key_bytes_set(vcap, &data,
472*4882a593Smuzhiyun VCAP_IS2_HK_MAC_ARP_L3_IP4_DIP,
473*4882a593Smuzhiyun arp->dip.value.addr, arp->dip.mask.addr);
474*4882a593Smuzhiyun vcap_key_bytes_set(vcap, &data,
475*4882a593Smuzhiyun VCAP_IS2_HK_MAC_ARP_L3_IP4_SIP,
476*4882a593Smuzhiyun arp->sip.value.addr, arp->sip.mask.addr);
477*4882a593Smuzhiyun vcap_key_set(vcap, &data, VCAP_IS2_HK_MAC_ARP_DIP_EQ_SIP,
478*4882a593Smuzhiyun 0, 0);
479*4882a593Smuzhiyun break;
480*4882a593Smuzhiyun }
481*4882a593Smuzhiyun case OCELOT_VCAP_KEY_IPV4:
482*4882a593Smuzhiyun case OCELOT_VCAP_KEY_IPV6: {
483*4882a593Smuzhiyun enum ocelot_vcap_bit sip_eq_dip, sport_eq_dport, seq_zero, tcp;
484*4882a593Smuzhiyun enum ocelot_vcap_bit ttl, fragment, options, tcp_ack, tcp_urg;
485*4882a593Smuzhiyun enum ocelot_vcap_bit tcp_fin, tcp_syn, tcp_rst, tcp_psh;
486*4882a593Smuzhiyun struct ocelot_vcap_key_ipv4 *ipv4 = NULL;
487*4882a593Smuzhiyun struct ocelot_vcap_key_ipv6 *ipv6 = NULL;
488*4882a593Smuzhiyun struct ocelot_vcap_udp_tcp *sport, *dport;
489*4882a593Smuzhiyun struct ocelot_vcap_ipv4 sip, dip;
490*4882a593Smuzhiyun struct ocelot_vcap_u8 proto, ds;
491*4882a593Smuzhiyun struct ocelot_vcap_u48 *ip_data;
492*4882a593Smuzhiyun
493*4882a593Smuzhiyun if (filter->key_type == OCELOT_VCAP_KEY_IPV4) {
494*4882a593Smuzhiyun ipv4 = &filter->key.ipv4;
495*4882a593Smuzhiyun ttl = ipv4->ttl;
496*4882a593Smuzhiyun fragment = ipv4->fragment;
497*4882a593Smuzhiyun options = ipv4->options;
498*4882a593Smuzhiyun proto = ipv4->proto;
499*4882a593Smuzhiyun ds = ipv4->ds;
500*4882a593Smuzhiyun ip_data = &ipv4->data;
501*4882a593Smuzhiyun sip = ipv4->sip;
502*4882a593Smuzhiyun dip = ipv4->dip;
503*4882a593Smuzhiyun sport = &ipv4->sport;
504*4882a593Smuzhiyun dport = &ipv4->dport;
505*4882a593Smuzhiyun tcp_fin = ipv4->tcp_fin;
506*4882a593Smuzhiyun tcp_syn = ipv4->tcp_syn;
507*4882a593Smuzhiyun tcp_rst = ipv4->tcp_rst;
508*4882a593Smuzhiyun tcp_psh = ipv4->tcp_psh;
509*4882a593Smuzhiyun tcp_ack = ipv4->tcp_ack;
510*4882a593Smuzhiyun tcp_urg = ipv4->tcp_urg;
511*4882a593Smuzhiyun sip_eq_dip = ipv4->sip_eq_dip;
512*4882a593Smuzhiyun sport_eq_dport = ipv4->sport_eq_dport;
513*4882a593Smuzhiyun seq_zero = ipv4->seq_zero;
514*4882a593Smuzhiyun } else {
515*4882a593Smuzhiyun ipv6 = &filter->key.ipv6;
516*4882a593Smuzhiyun ttl = ipv6->ttl;
517*4882a593Smuzhiyun fragment = OCELOT_VCAP_BIT_ANY;
518*4882a593Smuzhiyun options = OCELOT_VCAP_BIT_ANY;
519*4882a593Smuzhiyun proto = ipv6->proto;
520*4882a593Smuzhiyun ds = ipv6->ds;
521*4882a593Smuzhiyun ip_data = &ipv6->data;
522*4882a593Smuzhiyun for (i = 0; i < 8; i++) {
523*4882a593Smuzhiyun val = ipv6->sip.value[i + 8];
524*4882a593Smuzhiyun msk = ipv6->sip.mask[i + 8];
525*4882a593Smuzhiyun if (i < 4) {
526*4882a593Smuzhiyun dip.value.addr[i] = val;
527*4882a593Smuzhiyun dip.mask.addr[i] = msk;
528*4882a593Smuzhiyun } else {
529*4882a593Smuzhiyun sip.value.addr[i - 4] = val;
530*4882a593Smuzhiyun sip.mask.addr[i - 4] = msk;
531*4882a593Smuzhiyun }
532*4882a593Smuzhiyun }
533*4882a593Smuzhiyun sport = &ipv6->sport;
534*4882a593Smuzhiyun dport = &ipv6->dport;
535*4882a593Smuzhiyun tcp_fin = ipv6->tcp_fin;
536*4882a593Smuzhiyun tcp_syn = ipv6->tcp_syn;
537*4882a593Smuzhiyun tcp_rst = ipv6->tcp_rst;
538*4882a593Smuzhiyun tcp_psh = ipv6->tcp_psh;
539*4882a593Smuzhiyun tcp_ack = ipv6->tcp_ack;
540*4882a593Smuzhiyun tcp_urg = ipv6->tcp_urg;
541*4882a593Smuzhiyun sip_eq_dip = ipv6->sip_eq_dip;
542*4882a593Smuzhiyun sport_eq_dport = ipv6->sport_eq_dport;
543*4882a593Smuzhiyun seq_zero = ipv6->seq_zero;
544*4882a593Smuzhiyun }
545*4882a593Smuzhiyun
546*4882a593Smuzhiyun vcap_key_bit_set(vcap, &data, VCAP_IS2_HK_IP4,
547*4882a593Smuzhiyun ipv4 ? OCELOT_VCAP_BIT_1 : OCELOT_VCAP_BIT_0);
548*4882a593Smuzhiyun vcap_key_bit_set(vcap, &data, VCAP_IS2_HK_L3_FRAGMENT,
549*4882a593Smuzhiyun fragment);
550*4882a593Smuzhiyun vcap_key_set(vcap, &data, VCAP_IS2_HK_L3_FRAG_OFS_GT0, 0, 0);
551*4882a593Smuzhiyun vcap_key_bit_set(vcap, &data, VCAP_IS2_HK_L3_OPTIONS,
552*4882a593Smuzhiyun options);
553*4882a593Smuzhiyun vcap_key_bit_set(vcap, &data, VCAP_IS2_HK_IP4_L3_TTL_GT0,
554*4882a593Smuzhiyun ttl);
555*4882a593Smuzhiyun vcap_key_bytes_set(vcap, &data, VCAP_IS2_HK_L3_TOS,
556*4882a593Smuzhiyun ds.value, ds.mask);
557*4882a593Smuzhiyun vcap_key_bytes_set(vcap, &data, VCAP_IS2_HK_L3_IP4_DIP,
558*4882a593Smuzhiyun dip.value.addr, dip.mask.addr);
559*4882a593Smuzhiyun vcap_key_bytes_set(vcap, &data, VCAP_IS2_HK_L3_IP4_SIP,
560*4882a593Smuzhiyun sip.value.addr, sip.mask.addr);
561*4882a593Smuzhiyun vcap_key_bit_set(vcap, &data, VCAP_IS2_HK_DIP_EQ_SIP,
562*4882a593Smuzhiyun sip_eq_dip);
563*4882a593Smuzhiyun val = proto.value[0];
564*4882a593Smuzhiyun msk = proto.mask[0];
565*4882a593Smuzhiyun type = IS2_TYPE_IP_UDP_TCP;
566*4882a593Smuzhiyun if (msk == 0xff && (val == 6 || val == 17)) {
567*4882a593Smuzhiyun /* UDP/TCP protocol match */
568*4882a593Smuzhiyun tcp = (val == 6 ?
569*4882a593Smuzhiyun OCELOT_VCAP_BIT_1 : OCELOT_VCAP_BIT_0);
570*4882a593Smuzhiyun vcap_key_bit_set(vcap, &data, VCAP_IS2_HK_TCP, tcp);
571*4882a593Smuzhiyun vcap_key_l4_port_set(vcap, &data,
572*4882a593Smuzhiyun VCAP_IS2_HK_L4_DPORT, dport);
573*4882a593Smuzhiyun vcap_key_l4_port_set(vcap, &data,
574*4882a593Smuzhiyun VCAP_IS2_HK_L4_SPORT, sport);
575*4882a593Smuzhiyun vcap_key_set(vcap, &data, VCAP_IS2_HK_L4_RNG, 0, 0);
576*4882a593Smuzhiyun vcap_key_bit_set(vcap, &data,
577*4882a593Smuzhiyun VCAP_IS2_HK_L4_SPORT_EQ_DPORT,
578*4882a593Smuzhiyun sport_eq_dport);
579*4882a593Smuzhiyun vcap_key_bit_set(vcap, &data,
580*4882a593Smuzhiyun VCAP_IS2_HK_L4_SEQUENCE_EQ0,
581*4882a593Smuzhiyun seq_zero);
582*4882a593Smuzhiyun vcap_key_bit_set(vcap, &data, VCAP_IS2_HK_L4_FIN,
583*4882a593Smuzhiyun tcp_fin);
584*4882a593Smuzhiyun vcap_key_bit_set(vcap, &data, VCAP_IS2_HK_L4_SYN,
585*4882a593Smuzhiyun tcp_syn);
586*4882a593Smuzhiyun vcap_key_bit_set(vcap, &data, VCAP_IS2_HK_L4_RST,
587*4882a593Smuzhiyun tcp_rst);
588*4882a593Smuzhiyun vcap_key_bit_set(vcap, &data, VCAP_IS2_HK_L4_PSH,
589*4882a593Smuzhiyun tcp_psh);
590*4882a593Smuzhiyun vcap_key_bit_set(vcap, &data, VCAP_IS2_HK_L4_ACK,
591*4882a593Smuzhiyun tcp_ack);
592*4882a593Smuzhiyun vcap_key_bit_set(vcap, &data, VCAP_IS2_HK_L4_URG,
593*4882a593Smuzhiyun tcp_urg);
594*4882a593Smuzhiyun vcap_key_set(vcap, &data, VCAP_IS2_HK_L4_1588_DOM,
595*4882a593Smuzhiyun 0, 0);
596*4882a593Smuzhiyun vcap_key_set(vcap, &data, VCAP_IS2_HK_L4_1588_VER,
597*4882a593Smuzhiyun 0, 0);
598*4882a593Smuzhiyun } else {
599*4882a593Smuzhiyun if (msk == 0) {
600*4882a593Smuzhiyun /* Any IP protocol match */
601*4882a593Smuzhiyun type_mask = IS2_TYPE_MASK_IP_ANY;
602*4882a593Smuzhiyun } else {
603*4882a593Smuzhiyun /* Non-UDP/TCP protocol match */
604*4882a593Smuzhiyun type = IS2_TYPE_IP_OTHER;
605*4882a593Smuzhiyun for (i = 0; i < 6; i++) {
606*4882a593Smuzhiyun payload.value[i] = ip_data->value[i];
607*4882a593Smuzhiyun payload.mask[i] = ip_data->mask[i];
608*4882a593Smuzhiyun }
609*4882a593Smuzhiyun }
610*4882a593Smuzhiyun vcap_key_bytes_set(vcap, &data,
611*4882a593Smuzhiyun VCAP_IS2_HK_IP4_L3_PROTO,
612*4882a593Smuzhiyun proto.value, proto.mask);
613*4882a593Smuzhiyun vcap_key_bytes_set(vcap, &data,
614*4882a593Smuzhiyun VCAP_IS2_HK_L3_PAYLOAD,
615*4882a593Smuzhiyun payload.value, payload.mask);
616*4882a593Smuzhiyun }
617*4882a593Smuzhiyun break;
618*4882a593Smuzhiyun }
619*4882a593Smuzhiyun case OCELOT_VCAP_KEY_ANY:
620*4882a593Smuzhiyun default:
621*4882a593Smuzhiyun type = 0;
622*4882a593Smuzhiyun type_mask = 0;
623*4882a593Smuzhiyun count = vcap->entry_width / 2;
624*4882a593Smuzhiyun /* Iterate over the non-common part of the key and
625*4882a593Smuzhiyun * clear entry data
626*4882a593Smuzhiyun */
627*4882a593Smuzhiyun for (i = vcap->keys[VCAP_IS2_HK_L2_DMAC].offset;
628*4882a593Smuzhiyun i < count; i += ENTRY_WIDTH) {
629*4882a593Smuzhiyun vcap_key_field_set(&data, i, min(32u, count - i), 0, 0);
630*4882a593Smuzhiyun }
631*4882a593Smuzhiyun break;
632*4882a593Smuzhiyun }
633*4882a593Smuzhiyun
634*4882a593Smuzhiyun vcap_key_set(vcap, &data, VCAP_IS2_TYPE, type, type_mask);
635*4882a593Smuzhiyun is2_action_set(ocelot, &data, filter);
636*4882a593Smuzhiyun vcap_data_set(data.counter, data.counter_offset,
637*4882a593Smuzhiyun vcap->counter_width, filter->stats.pkts);
638*4882a593Smuzhiyun
639*4882a593Smuzhiyun /* Write row */
640*4882a593Smuzhiyun vcap_entry2cache(ocelot, vcap, &data);
641*4882a593Smuzhiyun vcap_action2cache(ocelot, vcap, &data);
642*4882a593Smuzhiyun vcap_row_cmd(ocelot, vcap, row, VCAP_CMD_WRITE, VCAP_SEL_ALL);
643*4882a593Smuzhiyun }
644*4882a593Smuzhiyun
is1_action_set(struct ocelot * ocelot,struct vcap_data * data,const struct ocelot_vcap_filter * filter)645*4882a593Smuzhiyun static void is1_action_set(struct ocelot *ocelot, struct vcap_data *data,
646*4882a593Smuzhiyun const struct ocelot_vcap_filter *filter)
647*4882a593Smuzhiyun {
648*4882a593Smuzhiyun const struct vcap_props *vcap = &ocelot->vcap[VCAP_IS1];
649*4882a593Smuzhiyun const struct ocelot_vcap_action *a = &filter->action;
650*4882a593Smuzhiyun
651*4882a593Smuzhiyun vcap_action_set(vcap, data, VCAP_IS1_ACT_VID_REPLACE_ENA,
652*4882a593Smuzhiyun a->vid_replace_ena);
653*4882a593Smuzhiyun vcap_action_set(vcap, data, VCAP_IS1_ACT_VID_ADD_VAL, a->vid);
654*4882a593Smuzhiyun vcap_action_set(vcap, data, VCAP_IS1_ACT_VLAN_POP_CNT_ENA,
655*4882a593Smuzhiyun a->vlan_pop_cnt_ena);
656*4882a593Smuzhiyun vcap_action_set(vcap, data, VCAP_IS1_ACT_VLAN_POP_CNT,
657*4882a593Smuzhiyun a->vlan_pop_cnt);
658*4882a593Smuzhiyun vcap_action_set(vcap, data, VCAP_IS1_ACT_PCP_DEI_ENA, a->pcp_dei_ena);
659*4882a593Smuzhiyun vcap_action_set(vcap, data, VCAP_IS1_ACT_PCP_VAL, a->pcp);
660*4882a593Smuzhiyun vcap_action_set(vcap, data, VCAP_IS1_ACT_DEI_VAL, a->dei);
661*4882a593Smuzhiyun vcap_action_set(vcap, data, VCAP_IS1_ACT_QOS_ENA, a->qos_ena);
662*4882a593Smuzhiyun vcap_action_set(vcap, data, VCAP_IS1_ACT_QOS_VAL, a->qos_val);
663*4882a593Smuzhiyun vcap_action_set(vcap, data, VCAP_IS1_ACT_PAG_OVERRIDE_MASK,
664*4882a593Smuzhiyun a->pag_override_mask);
665*4882a593Smuzhiyun vcap_action_set(vcap, data, VCAP_IS1_ACT_PAG_VAL, a->pag_val);
666*4882a593Smuzhiyun }
667*4882a593Smuzhiyun
is1_entry_set(struct ocelot * ocelot,int ix,struct ocelot_vcap_filter * filter)668*4882a593Smuzhiyun static void is1_entry_set(struct ocelot *ocelot, int ix,
669*4882a593Smuzhiyun struct ocelot_vcap_filter *filter)
670*4882a593Smuzhiyun {
671*4882a593Smuzhiyun const struct vcap_props *vcap = &ocelot->vcap[VCAP_IS1];
672*4882a593Smuzhiyun struct ocelot_vcap_key_vlan *tag = &filter->vlan;
673*4882a593Smuzhiyun struct ocelot_vcap_u64 payload;
674*4882a593Smuzhiyun struct vcap_data data;
675*4882a593Smuzhiyun int row = ix / 2;
676*4882a593Smuzhiyun u32 type;
677*4882a593Smuzhiyun
678*4882a593Smuzhiyun memset(&payload, 0, sizeof(payload));
679*4882a593Smuzhiyun memset(&data, 0, sizeof(data));
680*4882a593Smuzhiyun
681*4882a593Smuzhiyun /* Read row */
682*4882a593Smuzhiyun vcap_row_cmd(ocelot, vcap, row, VCAP_CMD_READ, VCAP_SEL_ALL);
683*4882a593Smuzhiyun vcap_cache2entry(ocelot, vcap, &data);
684*4882a593Smuzhiyun vcap_cache2action(ocelot, vcap, &data);
685*4882a593Smuzhiyun
686*4882a593Smuzhiyun data.tg_sw = VCAP_TG_HALF;
687*4882a593Smuzhiyun data.type = IS1_ACTION_TYPE_NORMAL;
688*4882a593Smuzhiyun vcap_data_offset_get(vcap, &data, ix);
689*4882a593Smuzhiyun data.tg = (data.tg & ~data.tg_mask);
690*4882a593Smuzhiyun if (filter->prio != 0)
691*4882a593Smuzhiyun data.tg |= data.tg_value;
692*4882a593Smuzhiyun
693*4882a593Smuzhiyun vcap_key_set(vcap, &data, VCAP_IS1_HK_LOOKUP, filter->lookup, 0x3);
694*4882a593Smuzhiyun vcap_key_set(vcap, &data, VCAP_IS1_HK_IGR_PORT_MASK, 0,
695*4882a593Smuzhiyun ~filter->ingress_port_mask);
696*4882a593Smuzhiyun vcap_key_bit_set(vcap, &data, VCAP_IS1_HK_L2_MC, filter->dmac_mc);
697*4882a593Smuzhiyun vcap_key_bit_set(vcap, &data, VCAP_IS1_HK_L2_BC, filter->dmac_bc);
698*4882a593Smuzhiyun vcap_key_bit_set(vcap, &data, VCAP_IS1_HK_VLAN_TAGGED, tag->tagged);
699*4882a593Smuzhiyun vcap_key_set(vcap, &data, VCAP_IS1_HK_VID,
700*4882a593Smuzhiyun tag->vid.value, tag->vid.mask);
701*4882a593Smuzhiyun vcap_key_set(vcap, &data, VCAP_IS1_HK_PCP,
702*4882a593Smuzhiyun tag->pcp.value[0], tag->pcp.mask[0]);
703*4882a593Smuzhiyun type = IS1_TYPE_S1_NORMAL;
704*4882a593Smuzhiyun
705*4882a593Smuzhiyun switch (filter->key_type) {
706*4882a593Smuzhiyun case OCELOT_VCAP_KEY_ETYPE: {
707*4882a593Smuzhiyun struct ocelot_vcap_key_etype *etype = &filter->key.etype;
708*4882a593Smuzhiyun
709*4882a593Smuzhiyun vcap_key_bytes_set(vcap, &data, VCAP_IS1_HK_L2_SMAC,
710*4882a593Smuzhiyun etype->smac.value, etype->smac.mask);
711*4882a593Smuzhiyun vcap_key_bytes_set(vcap, &data, VCAP_IS1_HK_ETYPE,
712*4882a593Smuzhiyun etype->etype.value, etype->etype.mask);
713*4882a593Smuzhiyun break;
714*4882a593Smuzhiyun }
715*4882a593Smuzhiyun case OCELOT_VCAP_KEY_IPV4: {
716*4882a593Smuzhiyun struct ocelot_vcap_key_ipv4 *ipv4 = &filter->key.ipv4;
717*4882a593Smuzhiyun struct ocelot_vcap_udp_tcp *sport = &ipv4->sport;
718*4882a593Smuzhiyun struct ocelot_vcap_udp_tcp *dport = &ipv4->dport;
719*4882a593Smuzhiyun enum ocelot_vcap_bit tcp_udp = OCELOT_VCAP_BIT_0;
720*4882a593Smuzhiyun struct ocelot_vcap_u8 proto = ipv4->proto;
721*4882a593Smuzhiyun struct ocelot_vcap_ipv4 sip = ipv4->sip;
722*4882a593Smuzhiyun u32 val, msk;
723*4882a593Smuzhiyun
724*4882a593Smuzhiyun vcap_key_bit_set(vcap, &data, VCAP_IS1_HK_IP_SNAP,
725*4882a593Smuzhiyun OCELOT_VCAP_BIT_1);
726*4882a593Smuzhiyun vcap_key_bit_set(vcap, &data, VCAP_IS1_HK_IP4,
727*4882a593Smuzhiyun OCELOT_VCAP_BIT_1);
728*4882a593Smuzhiyun vcap_key_bit_set(vcap, &data, VCAP_IS1_HK_ETYPE_LEN,
729*4882a593Smuzhiyun OCELOT_VCAP_BIT_1);
730*4882a593Smuzhiyun vcap_key_bytes_set(vcap, &data, VCAP_IS1_HK_L3_IP4_SIP,
731*4882a593Smuzhiyun sip.value.addr, sip.mask.addr);
732*4882a593Smuzhiyun
733*4882a593Smuzhiyun val = proto.value[0];
734*4882a593Smuzhiyun msk = proto.mask[0];
735*4882a593Smuzhiyun
736*4882a593Smuzhiyun if ((val == NEXTHDR_TCP || val == NEXTHDR_UDP) && msk == 0xff)
737*4882a593Smuzhiyun tcp_udp = OCELOT_VCAP_BIT_1;
738*4882a593Smuzhiyun vcap_key_bit_set(vcap, &data, VCAP_IS1_HK_TCP_UDP, tcp_udp);
739*4882a593Smuzhiyun
740*4882a593Smuzhiyun if (tcp_udp) {
741*4882a593Smuzhiyun enum ocelot_vcap_bit tcp = OCELOT_VCAP_BIT_0;
742*4882a593Smuzhiyun
743*4882a593Smuzhiyun if (val == NEXTHDR_TCP)
744*4882a593Smuzhiyun tcp = OCELOT_VCAP_BIT_1;
745*4882a593Smuzhiyun
746*4882a593Smuzhiyun vcap_key_bit_set(vcap, &data, VCAP_IS1_HK_TCP, tcp);
747*4882a593Smuzhiyun vcap_key_l4_port_set(vcap, &data, VCAP_IS1_HK_L4_SPORT,
748*4882a593Smuzhiyun sport);
749*4882a593Smuzhiyun /* Overloaded field */
750*4882a593Smuzhiyun vcap_key_l4_port_set(vcap, &data, VCAP_IS1_HK_ETYPE,
751*4882a593Smuzhiyun dport);
752*4882a593Smuzhiyun } else {
753*4882a593Smuzhiyun /* IPv4 "other" frame */
754*4882a593Smuzhiyun struct ocelot_vcap_u16 etype = {0};
755*4882a593Smuzhiyun
756*4882a593Smuzhiyun /* Overloaded field */
757*4882a593Smuzhiyun etype.value[0] = proto.value[0];
758*4882a593Smuzhiyun etype.mask[0] = proto.mask[0];
759*4882a593Smuzhiyun
760*4882a593Smuzhiyun vcap_key_bytes_set(vcap, &data, VCAP_IS1_HK_ETYPE,
761*4882a593Smuzhiyun etype.value, etype.mask);
762*4882a593Smuzhiyun }
763*4882a593Smuzhiyun }
764*4882a593Smuzhiyun default:
765*4882a593Smuzhiyun break;
766*4882a593Smuzhiyun }
767*4882a593Smuzhiyun vcap_key_bit_set(vcap, &data, VCAP_IS1_HK_TYPE,
768*4882a593Smuzhiyun type ? OCELOT_VCAP_BIT_1 : OCELOT_VCAP_BIT_0);
769*4882a593Smuzhiyun
770*4882a593Smuzhiyun is1_action_set(ocelot, &data, filter);
771*4882a593Smuzhiyun vcap_data_set(data.counter, data.counter_offset,
772*4882a593Smuzhiyun vcap->counter_width, filter->stats.pkts);
773*4882a593Smuzhiyun
774*4882a593Smuzhiyun /* Write row */
775*4882a593Smuzhiyun vcap_entry2cache(ocelot, vcap, &data);
776*4882a593Smuzhiyun vcap_action2cache(ocelot, vcap, &data);
777*4882a593Smuzhiyun vcap_row_cmd(ocelot, vcap, row, VCAP_CMD_WRITE, VCAP_SEL_ALL);
778*4882a593Smuzhiyun }
779*4882a593Smuzhiyun
es0_action_set(struct ocelot * ocelot,struct vcap_data * data,const struct ocelot_vcap_filter * filter)780*4882a593Smuzhiyun static void es0_action_set(struct ocelot *ocelot, struct vcap_data *data,
781*4882a593Smuzhiyun const struct ocelot_vcap_filter *filter)
782*4882a593Smuzhiyun {
783*4882a593Smuzhiyun const struct vcap_props *vcap = &ocelot->vcap[VCAP_ES0];
784*4882a593Smuzhiyun const struct ocelot_vcap_action *a = &filter->action;
785*4882a593Smuzhiyun
786*4882a593Smuzhiyun vcap_action_set(vcap, data, VCAP_ES0_ACT_PUSH_OUTER_TAG,
787*4882a593Smuzhiyun a->push_outer_tag);
788*4882a593Smuzhiyun vcap_action_set(vcap, data, VCAP_ES0_ACT_PUSH_INNER_TAG,
789*4882a593Smuzhiyun a->push_inner_tag);
790*4882a593Smuzhiyun vcap_action_set(vcap, data, VCAP_ES0_ACT_TAG_A_TPID_SEL,
791*4882a593Smuzhiyun a->tag_a_tpid_sel);
792*4882a593Smuzhiyun vcap_action_set(vcap, data, VCAP_ES0_ACT_TAG_A_VID_SEL,
793*4882a593Smuzhiyun a->tag_a_vid_sel);
794*4882a593Smuzhiyun vcap_action_set(vcap, data, VCAP_ES0_ACT_TAG_A_PCP_SEL,
795*4882a593Smuzhiyun a->tag_a_pcp_sel);
796*4882a593Smuzhiyun vcap_action_set(vcap, data, VCAP_ES0_ACT_VID_A_VAL, a->vid_a_val);
797*4882a593Smuzhiyun vcap_action_set(vcap, data, VCAP_ES0_ACT_PCP_A_VAL, a->pcp_a_val);
798*4882a593Smuzhiyun vcap_action_set(vcap, data, VCAP_ES0_ACT_TAG_B_TPID_SEL,
799*4882a593Smuzhiyun a->tag_b_tpid_sel);
800*4882a593Smuzhiyun vcap_action_set(vcap, data, VCAP_ES0_ACT_TAG_B_VID_SEL,
801*4882a593Smuzhiyun a->tag_b_vid_sel);
802*4882a593Smuzhiyun vcap_action_set(vcap, data, VCAP_ES0_ACT_TAG_B_PCP_SEL,
803*4882a593Smuzhiyun a->tag_b_pcp_sel);
804*4882a593Smuzhiyun vcap_action_set(vcap, data, VCAP_ES0_ACT_VID_B_VAL, a->vid_b_val);
805*4882a593Smuzhiyun vcap_action_set(vcap, data, VCAP_ES0_ACT_PCP_B_VAL, a->pcp_b_val);
806*4882a593Smuzhiyun }
807*4882a593Smuzhiyun
es0_entry_set(struct ocelot * ocelot,int ix,struct ocelot_vcap_filter * filter)808*4882a593Smuzhiyun static void es0_entry_set(struct ocelot *ocelot, int ix,
809*4882a593Smuzhiyun struct ocelot_vcap_filter *filter)
810*4882a593Smuzhiyun {
811*4882a593Smuzhiyun const struct vcap_props *vcap = &ocelot->vcap[VCAP_ES0];
812*4882a593Smuzhiyun struct ocelot_vcap_key_vlan *tag = &filter->vlan;
813*4882a593Smuzhiyun struct ocelot_vcap_u64 payload;
814*4882a593Smuzhiyun struct vcap_data data;
815*4882a593Smuzhiyun int row = ix;
816*4882a593Smuzhiyun
817*4882a593Smuzhiyun memset(&payload, 0, sizeof(payload));
818*4882a593Smuzhiyun memset(&data, 0, sizeof(data));
819*4882a593Smuzhiyun
820*4882a593Smuzhiyun /* Read row */
821*4882a593Smuzhiyun vcap_row_cmd(ocelot, vcap, row, VCAP_CMD_READ, VCAP_SEL_ALL);
822*4882a593Smuzhiyun vcap_cache2entry(ocelot, vcap, &data);
823*4882a593Smuzhiyun vcap_cache2action(ocelot, vcap, &data);
824*4882a593Smuzhiyun
825*4882a593Smuzhiyun data.tg_sw = VCAP_TG_FULL;
826*4882a593Smuzhiyun data.type = ES0_ACTION_TYPE_NORMAL;
827*4882a593Smuzhiyun vcap_data_offset_get(vcap, &data, ix);
828*4882a593Smuzhiyun data.tg = (data.tg & ~data.tg_mask);
829*4882a593Smuzhiyun if (filter->prio != 0)
830*4882a593Smuzhiyun data.tg |= data.tg_value;
831*4882a593Smuzhiyun
832*4882a593Smuzhiyun vcap_key_set(vcap, &data, VCAP_ES0_IGR_PORT, filter->ingress_port.value,
833*4882a593Smuzhiyun filter->ingress_port.mask);
834*4882a593Smuzhiyun vcap_key_set(vcap, &data, VCAP_ES0_EGR_PORT, filter->egress_port.value,
835*4882a593Smuzhiyun filter->egress_port.mask);
836*4882a593Smuzhiyun vcap_key_bit_set(vcap, &data, VCAP_ES0_L2_MC, filter->dmac_mc);
837*4882a593Smuzhiyun vcap_key_bit_set(vcap, &data, VCAP_ES0_L2_BC, filter->dmac_bc);
838*4882a593Smuzhiyun vcap_key_set(vcap, &data, VCAP_ES0_VID,
839*4882a593Smuzhiyun tag->vid.value, tag->vid.mask);
840*4882a593Smuzhiyun vcap_key_set(vcap, &data, VCAP_ES0_PCP,
841*4882a593Smuzhiyun tag->pcp.value[0], tag->pcp.mask[0]);
842*4882a593Smuzhiyun
843*4882a593Smuzhiyun es0_action_set(ocelot, &data, filter);
844*4882a593Smuzhiyun vcap_data_set(data.counter, data.counter_offset,
845*4882a593Smuzhiyun vcap->counter_width, filter->stats.pkts);
846*4882a593Smuzhiyun
847*4882a593Smuzhiyun /* Write row */
848*4882a593Smuzhiyun vcap_entry2cache(ocelot, vcap, &data);
849*4882a593Smuzhiyun vcap_action2cache(ocelot, vcap, &data);
850*4882a593Smuzhiyun vcap_row_cmd(ocelot, vcap, row, VCAP_CMD_WRITE, VCAP_SEL_ALL);
851*4882a593Smuzhiyun }
852*4882a593Smuzhiyun
vcap_entry_get(struct ocelot * ocelot,int ix,struct ocelot_vcap_filter * filter)853*4882a593Smuzhiyun static void vcap_entry_get(struct ocelot *ocelot, int ix,
854*4882a593Smuzhiyun struct ocelot_vcap_filter *filter)
855*4882a593Smuzhiyun {
856*4882a593Smuzhiyun const struct vcap_props *vcap = &ocelot->vcap[filter->block_id];
857*4882a593Smuzhiyun struct vcap_data data;
858*4882a593Smuzhiyun int row, count;
859*4882a593Smuzhiyun u32 cnt;
860*4882a593Smuzhiyun
861*4882a593Smuzhiyun if (filter->block_id == VCAP_ES0)
862*4882a593Smuzhiyun data.tg_sw = VCAP_TG_FULL;
863*4882a593Smuzhiyun else
864*4882a593Smuzhiyun data.tg_sw = VCAP_TG_HALF;
865*4882a593Smuzhiyun
866*4882a593Smuzhiyun count = (1 << (data.tg_sw - 1));
867*4882a593Smuzhiyun row = (ix / count);
868*4882a593Smuzhiyun vcap_row_cmd(ocelot, vcap, row, VCAP_CMD_READ, VCAP_SEL_COUNTER);
869*4882a593Smuzhiyun vcap_cache2action(ocelot, vcap, &data);
870*4882a593Smuzhiyun vcap_data_offset_get(vcap, &data, ix);
871*4882a593Smuzhiyun cnt = vcap_data_get(data.counter, data.counter_offset,
872*4882a593Smuzhiyun vcap->counter_width);
873*4882a593Smuzhiyun
874*4882a593Smuzhiyun filter->stats.pkts = cnt;
875*4882a593Smuzhiyun }
876*4882a593Smuzhiyun
vcap_entry_set(struct ocelot * ocelot,int ix,struct ocelot_vcap_filter * filter)877*4882a593Smuzhiyun static void vcap_entry_set(struct ocelot *ocelot, int ix,
878*4882a593Smuzhiyun struct ocelot_vcap_filter *filter)
879*4882a593Smuzhiyun {
880*4882a593Smuzhiyun if (filter->block_id == VCAP_IS1)
881*4882a593Smuzhiyun return is1_entry_set(ocelot, ix, filter);
882*4882a593Smuzhiyun if (filter->block_id == VCAP_IS2)
883*4882a593Smuzhiyun return is2_entry_set(ocelot, ix, filter);
884*4882a593Smuzhiyun if (filter->block_id == VCAP_ES0)
885*4882a593Smuzhiyun return es0_entry_set(ocelot, ix, filter);
886*4882a593Smuzhiyun }
887*4882a593Smuzhiyun
ocelot_vcap_policer_add(struct ocelot * ocelot,u32 pol_ix,struct ocelot_policer * pol)888*4882a593Smuzhiyun static int ocelot_vcap_policer_add(struct ocelot *ocelot, u32 pol_ix,
889*4882a593Smuzhiyun struct ocelot_policer *pol)
890*4882a593Smuzhiyun {
891*4882a593Smuzhiyun struct qos_policer_conf pp = { 0 };
892*4882a593Smuzhiyun
893*4882a593Smuzhiyun if (!pol)
894*4882a593Smuzhiyun return -EINVAL;
895*4882a593Smuzhiyun
896*4882a593Smuzhiyun pp.mode = MSCC_QOS_RATE_MODE_DATA;
897*4882a593Smuzhiyun pp.pir = pol->rate;
898*4882a593Smuzhiyun pp.pbs = pol->burst;
899*4882a593Smuzhiyun
900*4882a593Smuzhiyun return qos_policer_conf_set(ocelot, 0, pol_ix, &pp);
901*4882a593Smuzhiyun }
902*4882a593Smuzhiyun
ocelot_vcap_policer_del(struct ocelot * ocelot,struct ocelot_vcap_block * block,u32 pol_ix)903*4882a593Smuzhiyun static void ocelot_vcap_policer_del(struct ocelot *ocelot,
904*4882a593Smuzhiyun struct ocelot_vcap_block *block,
905*4882a593Smuzhiyun u32 pol_ix)
906*4882a593Smuzhiyun {
907*4882a593Smuzhiyun struct ocelot_vcap_filter *filter;
908*4882a593Smuzhiyun struct qos_policer_conf pp = {0};
909*4882a593Smuzhiyun int index = -1;
910*4882a593Smuzhiyun
911*4882a593Smuzhiyun if (pol_ix < block->pol_lpr)
912*4882a593Smuzhiyun return;
913*4882a593Smuzhiyun
914*4882a593Smuzhiyun list_for_each_entry(filter, &block->rules, list) {
915*4882a593Smuzhiyun index++;
916*4882a593Smuzhiyun if (filter->block_id == VCAP_IS2 &&
917*4882a593Smuzhiyun filter->action.police_ena &&
918*4882a593Smuzhiyun filter->action.pol_ix < pol_ix) {
919*4882a593Smuzhiyun filter->action.pol_ix += 1;
920*4882a593Smuzhiyun ocelot_vcap_policer_add(ocelot, filter->action.pol_ix,
921*4882a593Smuzhiyun &filter->action.pol);
922*4882a593Smuzhiyun is2_entry_set(ocelot, index, filter);
923*4882a593Smuzhiyun }
924*4882a593Smuzhiyun }
925*4882a593Smuzhiyun
926*4882a593Smuzhiyun pp.mode = MSCC_QOS_RATE_MODE_DISABLED;
927*4882a593Smuzhiyun qos_policer_conf_set(ocelot, 0, pol_ix, &pp);
928*4882a593Smuzhiyun
929*4882a593Smuzhiyun block->pol_lpr++;
930*4882a593Smuzhiyun }
931*4882a593Smuzhiyun
ocelot_vcap_filter_add_to_block(struct ocelot * ocelot,struct ocelot_vcap_block * block,struct ocelot_vcap_filter * filter)932*4882a593Smuzhiyun static void ocelot_vcap_filter_add_to_block(struct ocelot *ocelot,
933*4882a593Smuzhiyun struct ocelot_vcap_block *block,
934*4882a593Smuzhiyun struct ocelot_vcap_filter *filter)
935*4882a593Smuzhiyun {
936*4882a593Smuzhiyun struct ocelot_vcap_filter *tmp;
937*4882a593Smuzhiyun struct list_head *pos, *n;
938*4882a593Smuzhiyun
939*4882a593Smuzhiyun if (filter->block_id == VCAP_IS2 && filter->action.police_ena) {
940*4882a593Smuzhiyun block->pol_lpr--;
941*4882a593Smuzhiyun filter->action.pol_ix = block->pol_lpr;
942*4882a593Smuzhiyun ocelot_vcap_policer_add(ocelot, filter->action.pol_ix,
943*4882a593Smuzhiyun &filter->action.pol);
944*4882a593Smuzhiyun }
945*4882a593Smuzhiyun
946*4882a593Smuzhiyun block->count++;
947*4882a593Smuzhiyun
948*4882a593Smuzhiyun if (list_empty(&block->rules)) {
949*4882a593Smuzhiyun list_add(&filter->list, &block->rules);
950*4882a593Smuzhiyun return;
951*4882a593Smuzhiyun }
952*4882a593Smuzhiyun
953*4882a593Smuzhiyun list_for_each_safe(pos, n, &block->rules) {
954*4882a593Smuzhiyun tmp = list_entry(pos, struct ocelot_vcap_filter, list);
955*4882a593Smuzhiyun if (filter->prio < tmp->prio)
956*4882a593Smuzhiyun break;
957*4882a593Smuzhiyun }
958*4882a593Smuzhiyun list_add(&filter->list, pos->prev);
959*4882a593Smuzhiyun }
960*4882a593Smuzhiyun
ocelot_vcap_block_get_filter_index(struct ocelot_vcap_block * block,struct ocelot_vcap_filter * filter)961*4882a593Smuzhiyun static int ocelot_vcap_block_get_filter_index(struct ocelot_vcap_block *block,
962*4882a593Smuzhiyun struct ocelot_vcap_filter *filter)
963*4882a593Smuzhiyun {
964*4882a593Smuzhiyun struct ocelot_vcap_filter *tmp;
965*4882a593Smuzhiyun int index = 0;
966*4882a593Smuzhiyun
967*4882a593Smuzhiyun list_for_each_entry(tmp, &block->rules, list) {
968*4882a593Smuzhiyun if (filter->id == tmp->id)
969*4882a593Smuzhiyun return index;
970*4882a593Smuzhiyun index++;
971*4882a593Smuzhiyun }
972*4882a593Smuzhiyun
973*4882a593Smuzhiyun return -ENOENT;
974*4882a593Smuzhiyun }
975*4882a593Smuzhiyun
976*4882a593Smuzhiyun static struct ocelot_vcap_filter*
ocelot_vcap_block_find_filter_by_index(struct ocelot_vcap_block * block,int index)977*4882a593Smuzhiyun ocelot_vcap_block_find_filter_by_index(struct ocelot_vcap_block *block,
978*4882a593Smuzhiyun int index)
979*4882a593Smuzhiyun {
980*4882a593Smuzhiyun struct ocelot_vcap_filter *tmp;
981*4882a593Smuzhiyun int i = 0;
982*4882a593Smuzhiyun
983*4882a593Smuzhiyun list_for_each_entry(tmp, &block->rules, list) {
984*4882a593Smuzhiyun if (i == index)
985*4882a593Smuzhiyun return tmp;
986*4882a593Smuzhiyun ++i;
987*4882a593Smuzhiyun }
988*4882a593Smuzhiyun
989*4882a593Smuzhiyun return NULL;
990*4882a593Smuzhiyun }
991*4882a593Smuzhiyun
992*4882a593Smuzhiyun struct ocelot_vcap_filter *
ocelot_vcap_block_find_filter_by_id(struct ocelot_vcap_block * block,int id)993*4882a593Smuzhiyun ocelot_vcap_block_find_filter_by_id(struct ocelot_vcap_block *block, int id)
994*4882a593Smuzhiyun {
995*4882a593Smuzhiyun struct ocelot_vcap_filter *filter;
996*4882a593Smuzhiyun
997*4882a593Smuzhiyun list_for_each_entry(filter, &block->rules, list)
998*4882a593Smuzhiyun if (filter->id == id)
999*4882a593Smuzhiyun return filter;
1000*4882a593Smuzhiyun
1001*4882a593Smuzhiyun return NULL;
1002*4882a593Smuzhiyun }
1003*4882a593Smuzhiyun
1004*4882a593Smuzhiyun /* If @on=false, then SNAP, ARP, IP and OAM frames will not match on keys based
1005*4882a593Smuzhiyun * on destination and source MAC addresses, but only on higher-level protocol
1006*4882a593Smuzhiyun * information. The only frame types to match on keys containing MAC addresses
1007*4882a593Smuzhiyun * in this case are non-SNAP, non-ARP, non-IP and non-OAM frames.
1008*4882a593Smuzhiyun *
1009*4882a593Smuzhiyun * If @on=true, then the above frame types (SNAP, ARP, IP and OAM) will match
1010*4882a593Smuzhiyun * on MAC_ETYPE keys such as destination and source MAC on this ingress port.
1011*4882a593Smuzhiyun * However the setting has the side effect of making these frames not matching
1012*4882a593Smuzhiyun * on any _other_ keys than MAC_ETYPE ones.
1013*4882a593Smuzhiyun */
ocelot_match_all_as_mac_etype(struct ocelot * ocelot,int port,int lookup,bool on)1014*4882a593Smuzhiyun static void ocelot_match_all_as_mac_etype(struct ocelot *ocelot, int port,
1015*4882a593Smuzhiyun int lookup, bool on)
1016*4882a593Smuzhiyun {
1017*4882a593Smuzhiyun u32 val = 0;
1018*4882a593Smuzhiyun
1019*4882a593Smuzhiyun if (on)
1020*4882a593Smuzhiyun val = ANA_PORT_VCAP_S2_CFG_S2_SNAP_DIS(BIT(lookup)) |
1021*4882a593Smuzhiyun ANA_PORT_VCAP_S2_CFG_S2_ARP_DIS(BIT(lookup)) |
1022*4882a593Smuzhiyun ANA_PORT_VCAP_S2_CFG_S2_IP_TCPUDP_DIS(BIT(lookup)) |
1023*4882a593Smuzhiyun ANA_PORT_VCAP_S2_CFG_S2_IP_OTHER_DIS(BIT(lookup)) |
1024*4882a593Smuzhiyun ANA_PORT_VCAP_S2_CFG_S2_OAM_DIS(BIT(lookup));
1025*4882a593Smuzhiyun
1026*4882a593Smuzhiyun ocelot_rmw_gix(ocelot, val,
1027*4882a593Smuzhiyun ANA_PORT_VCAP_S2_CFG_S2_SNAP_DIS(BIT(lookup)) |
1028*4882a593Smuzhiyun ANA_PORT_VCAP_S2_CFG_S2_ARP_DIS(BIT(lookup)) |
1029*4882a593Smuzhiyun ANA_PORT_VCAP_S2_CFG_S2_IP_TCPUDP_DIS(BIT(lookup)) |
1030*4882a593Smuzhiyun ANA_PORT_VCAP_S2_CFG_S2_IP_OTHER_DIS(BIT(lookup)) |
1031*4882a593Smuzhiyun ANA_PORT_VCAP_S2_CFG_S2_OAM_DIS(BIT(lookup)),
1032*4882a593Smuzhiyun ANA_PORT_VCAP_S2_CFG, port);
1033*4882a593Smuzhiyun }
1034*4882a593Smuzhiyun
1035*4882a593Smuzhiyun static bool
ocelot_vcap_is_problematic_mac_etype(struct ocelot_vcap_filter * filter)1036*4882a593Smuzhiyun ocelot_vcap_is_problematic_mac_etype(struct ocelot_vcap_filter *filter)
1037*4882a593Smuzhiyun {
1038*4882a593Smuzhiyun u16 proto, mask;
1039*4882a593Smuzhiyun
1040*4882a593Smuzhiyun if (filter->key_type != OCELOT_VCAP_KEY_ETYPE)
1041*4882a593Smuzhiyun return false;
1042*4882a593Smuzhiyun
1043*4882a593Smuzhiyun proto = ntohs(*(__be16 *)filter->key.etype.etype.value);
1044*4882a593Smuzhiyun mask = ntohs(*(__be16 *)filter->key.etype.etype.mask);
1045*4882a593Smuzhiyun
1046*4882a593Smuzhiyun /* ETH_P_ALL match, so all protocols below are included */
1047*4882a593Smuzhiyun if (mask == 0)
1048*4882a593Smuzhiyun return true;
1049*4882a593Smuzhiyun if (proto == ETH_P_ARP)
1050*4882a593Smuzhiyun return true;
1051*4882a593Smuzhiyun if (proto == ETH_P_IP)
1052*4882a593Smuzhiyun return true;
1053*4882a593Smuzhiyun if (proto == ETH_P_IPV6)
1054*4882a593Smuzhiyun return true;
1055*4882a593Smuzhiyun
1056*4882a593Smuzhiyun return false;
1057*4882a593Smuzhiyun }
1058*4882a593Smuzhiyun
1059*4882a593Smuzhiyun static bool
ocelot_vcap_is_problematic_non_mac_etype(struct ocelot_vcap_filter * filter)1060*4882a593Smuzhiyun ocelot_vcap_is_problematic_non_mac_etype(struct ocelot_vcap_filter *filter)
1061*4882a593Smuzhiyun {
1062*4882a593Smuzhiyun if (filter->key_type == OCELOT_VCAP_KEY_SNAP)
1063*4882a593Smuzhiyun return true;
1064*4882a593Smuzhiyun if (filter->key_type == OCELOT_VCAP_KEY_ARP)
1065*4882a593Smuzhiyun return true;
1066*4882a593Smuzhiyun if (filter->key_type == OCELOT_VCAP_KEY_IPV4)
1067*4882a593Smuzhiyun return true;
1068*4882a593Smuzhiyun if (filter->key_type == OCELOT_VCAP_KEY_IPV6)
1069*4882a593Smuzhiyun return true;
1070*4882a593Smuzhiyun return false;
1071*4882a593Smuzhiyun }
1072*4882a593Smuzhiyun
1073*4882a593Smuzhiyun static bool
ocelot_exclusive_mac_etype_filter_rules(struct ocelot * ocelot,struct ocelot_vcap_filter * filter)1074*4882a593Smuzhiyun ocelot_exclusive_mac_etype_filter_rules(struct ocelot *ocelot,
1075*4882a593Smuzhiyun struct ocelot_vcap_filter *filter)
1076*4882a593Smuzhiyun {
1077*4882a593Smuzhiyun struct ocelot_vcap_block *block = &ocelot->block[filter->block_id];
1078*4882a593Smuzhiyun struct ocelot_vcap_filter *tmp;
1079*4882a593Smuzhiyun unsigned long port;
1080*4882a593Smuzhiyun int i;
1081*4882a593Smuzhiyun
1082*4882a593Smuzhiyun /* We only have the S2_IP_TCPUDP_DIS set of knobs for VCAP IS2 */
1083*4882a593Smuzhiyun if (filter->block_id != VCAP_IS2)
1084*4882a593Smuzhiyun return true;
1085*4882a593Smuzhiyun
1086*4882a593Smuzhiyun if (ocelot_vcap_is_problematic_mac_etype(filter)) {
1087*4882a593Smuzhiyun /* Search for any non-MAC_ETYPE rules on the port */
1088*4882a593Smuzhiyun for (i = 0; i < block->count; i++) {
1089*4882a593Smuzhiyun tmp = ocelot_vcap_block_find_filter_by_index(block, i);
1090*4882a593Smuzhiyun if (tmp->ingress_port_mask & filter->ingress_port_mask &&
1091*4882a593Smuzhiyun tmp->lookup == filter->lookup &&
1092*4882a593Smuzhiyun ocelot_vcap_is_problematic_non_mac_etype(tmp))
1093*4882a593Smuzhiyun return false;
1094*4882a593Smuzhiyun }
1095*4882a593Smuzhiyun
1096*4882a593Smuzhiyun for_each_set_bit(port, &filter->ingress_port_mask,
1097*4882a593Smuzhiyun ocelot->num_phys_ports)
1098*4882a593Smuzhiyun ocelot_match_all_as_mac_etype(ocelot, port,
1099*4882a593Smuzhiyun filter->lookup, true);
1100*4882a593Smuzhiyun } else if (ocelot_vcap_is_problematic_non_mac_etype(filter)) {
1101*4882a593Smuzhiyun /* Search for any MAC_ETYPE rules on the port */
1102*4882a593Smuzhiyun for (i = 0; i < block->count; i++) {
1103*4882a593Smuzhiyun tmp = ocelot_vcap_block_find_filter_by_index(block, i);
1104*4882a593Smuzhiyun if (tmp->ingress_port_mask & filter->ingress_port_mask &&
1105*4882a593Smuzhiyun tmp->lookup == filter->lookup &&
1106*4882a593Smuzhiyun ocelot_vcap_is_problematic_mac_etype(tmp))
1107*4882a593Smuzhiyun return false;
1108*4882a593Smuzhiyun }
1109*4882a593Smuzhiyun
1110*4882a593Smuzhiyun for_each_set_bit(port, &filter->ingress_port_mask,
1111*4882a593Smuzhiyun ocelot->num_phys_ports)
1112*4882a593Smuzhiyun ocelot_match_all_as_mac_etype(ocelot, port,
1113*4882a593Smuzhiyun filter->lookup, false);
1114*4882a593Smuzhiyun }
1115*4882a593Smuzhiyun
1116*4882a593Smuzhiyun return true;
1117*4882a593Smuzhiyun }
1118*4882a593Smuzhiyun
ocelot_vcap_filter_add(struct ocelot * ocelot,struct ocelot_vcap_filter * filter,struct netlink_ext_ack * extack)1119*4882a593Smuzhiyun int ocelot_vcap_filter_add(struct ocelot *ocelot,
1120*4882a593Smuzhiyun struct ocelot_vcap_filter *filter,
1121*4882a593Smuzhiyun struct netlink_ext_ack *extack)
1122*4882a593Smuzhiyun {
1123*4882a593Smuzhiyun struct ocelot_vcap_block *block = &ocelot->block[filter->block_id];
1124*4882a593Smuzhiyun int i, index;
1125*4882a593Smuzhiyun
1126*4882a593Smuzhiyun if (!ocelot_exclusive_mac_etype_filter_rules(ocelot, filter)) {
1127*4882a593Smuzhiyun NL_SET_ERR_MSG_MOD(extack,
1128*4882a593Smuzhiyun "Cannot mix MAC_ETYPE with non-MAC_ETYPE rules, use the other IS2 lookup");
1129*4882a593Smuzhiyun return -EBUSY;
1130*4882a593Smuzhiyun }
1131*4882a593Smuzhiyun
1132*4882a593Smuzhiyun /* Add filter to the linked list */
1133*4882a593Smuzhiyun ocelot_vcap_filter_add_to_block(ocelot, block, filter);
1134*4882a593Smuzhiyun
1135*4882a593Smuzhiyun /* Get the index of the inserted filter */
1136*4882a593Smuzhiyun index = ocelot_vcap_block_get_filter_index(block, filter);
1137*4882a593Smuzhiyun if (index < 0)
1138*4882a593Smuzhiyun return index;
1139*4882a593Smuzhiyun
1140*4882a593Smuzhiyun /* Move down the rules to make place for the new filter */
1141*4882a593Smuzhiyun for (i = block->count - 1; i > index; i--) {
1142*4882a593Smuzhiyun struct ocelot_vcap_filter *tmp;
1143*4882a593Smuzhiyun
1144*4882a593Smuzhiyun tmp = ocelot_vcap_block_find_filter_by_index(block, i);
1145*4882a593Smuzhiyun /* Read back the filter's counters before moving it */
1146*4882a593Smuzhiyun vcap_entry_get(ocelot, i - 1, tmp);
1147*4882a593Smuzhiyun vcap_entry_set(ocelot, i, tmp);
1148*4882a593Smuzhiyun }
1149*4882a593Smuzhiyun
1150*4882a593Smuzhiyun /* Now insert the new filter */
1151*4882a593Smuzhiyun vcap_entry_set(ocelot, index, filter);
1152*4882a593Smuzhiyun return 0;
1153*4882a593Smuzhiyun }
1154*4882a593Smuzhiyun
ocelot_vcap_block_remove_filter(struct ocelot * ocelot,struct ocelot_vcap_block * block,struct ocelot_vcap_filter * filter)1155*4882a593Smuzhiyun static void ocelot_vcap_block_remove_filter(struct ocelot *ocelot,
1156*4882a593Smuzhiyun struct ocelot_vcap_block *block,
1157*4882a593Smuzhiyun struct ocelot_vcap_filter *filter)
1158*4882a593Smuzhiyun {
1159*4882a593Smuzhiyun struct ocelot_vcap_filter *tmp;
1160*4882a593Smuzhiyun struct list_head *pos, *q;
1161*4882a593Smuzhiyun
1162*4882a593Smuzhiyun list_for_each_safe(pos, q, &block->rules) {
1163*4882a593Smuzhiyun tmp = list_entry(pos, struct ocelot_vcap_filter, list);
1164*4882a593Smuzhiyun if (tmp->id == filter->id) {
1165*4882a593Smuzhiyun if (tmp->block_id == VCAP_IS2 &&
1166*4882a593Smuzhiyun tmp->action.police_ena)
1167*4882a593Smuzhiyun ocelot_vcap_policer_del(ocelot, block,
1168*4882a593Smuzhiyun tmp->action.pol_ix);
1169*4882a593Smuzhiyun
1170*4882a593Smuzhiyun list_del(pos);
1171*4882a593Smuzhiyun kfree(tmp);
1172*4882a593Smuzhiyun }
1173*4882a593Smuzhiyun }
1174*4882a593Smuzhiyun
1175*4882a593Smuzhiyun block->count--;
1176*4882a593Smuzhiyun }
1177*4882a593Smuzhiyun
ocelot_vcap_filter_del(struct ocelot * ocelot,struct ocelot_vcap_filter * filter)1178*4882a593Smuzhiyun int ocelot_vcap_filter_del(struct ocelot *ocelot,
1179*4882a593Smuzhiyun struct ocelot_vcap_filter *filter)
1180*4882a593Smuzhiyun {
1181*4882a593Smuzhiyun struct ocelot_vcap_block *block = &ocelot->block[filter->block_id];
1182*4882a593Smuzhiyun struct ocelot_vcap_filter del_filter;
1183*4882a593Smuzhiyun int i, index;
1184*4882a593Smuzhiyun
1185*4882a593Smuzhiyun /* Need to inherit the block_id so that vcap_entry_set()
1186*4882a593Smuzhiyun * does not get confused and knows where to install it.
1187*4882a593Smuzhiyun */
1188*4882a593Smuzhiyun memset(&del_filter, 0, sizeof(del_filter));
1189*4882a593Smuzhiyun del_filter.block_id = filter->block_id;
1190*4882a593Smuzhiyun
1191*4882a593Smuzhiyun /* Gets index of the filter */
1192*4882a593Smuzhiyun index = ocelot_vcap_block_get_filter_index(block, filter);
1193*4882a593Smuzhiyun if (index < 0)
1194*4882a593Smuzhiyun return index;
1195*4882a593Smuzhiyun
1196*4882a593Smuzhiyun /* Delete filter */
1197*4882a593Smuzhiyun ocelot_vcap_block_remove_filter(ocelot, block, filter);
1198*4882a593Smuzhiyun
1199*4882a593Smuzhiyun /* Move up all the blocks over the deleted filter */
1200*4882a593Smuzhiyun for (i = index; i < block->count; i++) {
1201*4882a593Smuzhiyun struct ocelot_vcap_filter *tmp;
1202*4882a593Smuzhiyun
1203*4882a593Smuzhiyun tmp = ocelot_vcap_block_find_filter_by_index(block, i);
1204*4882a593Smuzhiyun /* Read back the filter's counters before moving it */
1205*4882a593Smuzhiyun vcap_entry_get(ocelot, i + 1, tmp);
1206*4882a593Smuzhiyun vcap_entry_set(ocelot, i, tmp);
1207*4882a593Smuzhiyun }
1208*4882a593Smuzhiyun
1209*4882a593Smuzhiyun /* Now delete the last filter, because it is duplicated */
1210*4882a593Smuzhiyun vcap_entry_set(ocelot, block->count, &del_filter);
1211*4882a593Smuzhiyun
1212*4882a593Smuzhiyun return 0;
1213*4882a593Smuzhiyun }
1214*4882a593Smuzhiyun
ocelot_vcap_filter_stats_update(struct ocelot * ocelot,struct ocelot_vcap_filter * filter)1215*4882a593Smuzhiyun int ocelot_vcap_filter_stats_update(struct ocelot *ocelot,
1216*4882a593Smuzhiyun struct ocelot_vcap_filter *filter)
1217*4882a593Smuzhiyun {
1218*4882a593Smuzhiyun struct ocelot_vcap_block *block = &ocelot->block[filter->block_id];
1219*4882a593Smuzhiyun struct ocelot_vcap_filter tmp;
1220*4882a593Smuzhiyun int index;
1221*4882a593Smuzhiyun
1222*4882a593Smuzhiyun index = ocelot_vcap_block_get_filter_index(block, filter);
1223*4882a593Smuzhiyun if (index < 0)
1224*4882a593Smuzhiyun return index;
1225*4882a593Smuzhiyun
1226*4882a593Smuzhiyun vcap_entry_get(ocelot, index, filter);
1227*4882a593Smuzhiyun
1228*4882a593Smuzhiyun /* After we get the result we need to clear the counters */
1229*4882a593Smuzhiyun tmp = *filter;
1230*4882a593Smuzhiyun tmp.stats.pkts = 0;
1231*4882a593Smuzhiyun vcap_entry_set(ocelot, index, &tmp);
1232*4882a593Smuzhiyun
1233*4882a593Smuzhiyun return 0;
1234*4882a593Smuzhiyun }
1235*4882a593Smuzhiyun
ocelot_vcap_init_one(struct ocelot * ocelot,const struct vcap_props * vcap)1236*4882a593Smuzhiyun static void ocelot_vcap_init_one(struct ocelot *ocelot,
1237*4882a593Smuzhiyun const struct vcap_props *vcap)
1238*4882a593Smuzhiyun {
1239*4882a593Smuzhiyun struct vcap_data data;
1240*4882a593Smuzhiyun
1241*4882a593Smuzhiyun memset(&data, 0, sizeof(data));
1242*4882a593Smuzhiyun
1243*4882a593Smuzhiyun vcap_entry2cache(ocelot, vcap, &data);
1244*4882a593Smuzhiyun ocelot_target_write(ocelot, vcap->target, vcap->entry_count,
1245*4882a593Smuzhiyun VCAP_CORE_MV_CFG);
1246*4882a593Smuzhiyun vcap_cmd(ocelot, vcap, 0, VCAP_CMD_INITIALIZE, VCAP_SEL_ENTRY);
1247*4882a593Smuzhiyun
1248*4882a593Smuzhiyun vcap_action2cache(ocelot, vcap, &data);
1249*4882a593Smuzhiyun ocelot_target_write(ocelot, vcap->target, vcap->action_count,
1250*4882a593Smuzhiyun VCAP_CORE_MV_CFG);
1251*4882a593Smuzhiyun vcap_cmd(ocelot, vcap, 0, VCAP_CMD_INITIALIZE,
1252*4882a593Smuzhiyun VCAP_SEL_ACTION | VCAP_SEL_COUNTER);
1253*4882a593Smuzhiyun }
1254*4882a593Smuzhiyun
ocelot_vcap_detect_constants(struct ocelot * ocelot,struct vcap_props * vcap)1255*4882a593Smuzhiyun static void ocelot_vcap_detect_constants(struct ocelot *ocelot,
1256*4882a593Smuzhiyun struct vcap_props *vcap)
1257*4882a593Smuzhiyun {
1258*4882a593Smuzhiyun int counter_memory_width;
1259*4882a593Smuzhiyun int num_default_actions;
1260*4882a593Smuzhiyun int version;
1261*4882a593Smuzhiyun
1262*4882a593Smuzhiyun version = ocelot_target_read(ocelot, vcap->target,
1263*4882a593Smuzhiyun VCAP_CONST_VCAP_VER);
1264*4882a593Smuzhiyun /* Only version 0 VCAP supported for now */
1265*4882a593Smuzhiyun if (WARN_ON(version != 0))
1266*4882a593Smuzhiyun return;
1267*4882a593Smuzhiyun
1268*4882a593Smuzhiyun /* Width in bits of type-group field */
1269*4882a593Smuzhiyun vcap->tg_width = ocelot_target_read(ocelot, vcap->target,
1270*4882a593Smuzhiyun VCAP_CONST_ENTRY_TG_WIDTH);
1271*4882a593Smuzhiyun /* Number of subwords per TCAM row */
1272*4882a593Smuzhiyun vcap->sw_count = ocelot_target_read(ocelot, vcap->target,
1273*4882a593Smuzhiyun VCAP_CONST_ENTRY_SWCNT);
1274*4882a593Smuzhiyun /* Number of rows in TCAM. There can be this many full keys, or double
1275*4882a593Smuzhiyun * this number half keys, or 4 times this number quarter keys.
1276*4882a593Smuzhiyun */
1277*4882a593Smuzhiyun vcap->entry_count = ocelot_target_read(ocelot, vcap->target,
1278*4882a593Smuzhiyun VCAP_CONST_ENTRY_CNT);
1279*4882a593Smuzhiyun /* Assuming there are 4 subwords per TCAM row, their layout in the
1280*4882a593Smuzhiyun * actual TCAM (not in the cache) would be:
1281*4882a593Smuzhiyun *
1282*4882a593Smuzhiyun * | SW 3 | TG 3 | SW 2 | TG 2 | SW 1 | TG 1 | SW 0 | TG 0 |
1283*4882a593Smuzhiyun *
1284*4882a593Smuzhiyun * (where SW=subword and TG=Type-Group).
1285*4882a593Smuzhiyun *
1286*4882a593Smuzhiyun * What VCAP_CONST_ENTRY_CNT is giving us is the width of one full TCAM
1287*4882a593Smuzhiyun * row. But when software accesses the TCAM through the cache
1288*4882a593Smuzhiyun * registers, the Type-Group values are written through another set of
1289*4882a593Smuzhiyun * registers VCAP_TG_DAT, and therefore, it appears as though the 4
1290*4882a593Smuzhiyun * subwords are contiguous in the cache memory.
1291*4882a593Smuzhiyun * Important mention: regardless of the number of key entries per row
1292*4882a593Smuzhiyun * (and therefore of key size: 1 full key or 2 half keys or 4 quarter
1293*4882a593Smuzhiyun * keys), software always has to configure 4 Type-Group values. For
1294*4882a593Smuzhiyun * example, in the case of 1 full key, the driver needs to set all 4
1295*4882a593Smuzhiyun * Type-Group to be full key.
1296*4882a593Smuzhiyun *
1297*4882a593Smuzhiyun * For this reason, we need to fix up the value that the hardware is
1298*4882a593Smuzhiyun * giving us. We don't actually care about the width of the entry in
1299*4882a593Smuzhiyun * the TCAM. What we care about is the width of the entry in the cache
1300*4882a593Smuzhiyun * registers, which is how we get to interact with it. And since the
1301*4882a593Smuzhiyun * VCAP_ENTRY_DAT cache registers access only the subwords and not the
1302*4882a593Smuzhiyun * Type-Groups, this means we need to subtract the width of the
1303*4882a593Smuzhiyun * Type-Groups when packing and unpacking key entry data in a TCAM row.
1304*4882a593Smuzhiyun */
1305*4882a593Smuzhiyun vcap->entry_width = ocelot_target_read(ocelot, vcap->target,
1306*4882a593Smuzhiyun VCAP_CONST_ENTRY_WIDTH);
1307*4882a593Smuzhiyun vcap->entry_width -= vcap->tg_width * vcap->sw_count;
1308*4882a593Smuzhiyun num_default_actions = ocelot_target_read(ocelot, vcap->target,
1309*4882a593Smuzhiyun VCAP_CONST_ACTION_DEF_CNT);
1310*4882a593Smuzhiyun vcap->action_count = vcap->entry_count + num_default_actions;
1311*4882a593Smuzhiyun vcap->action_width = ocelot_target_read(ocelot, vcap->target,
1312*4882a593Smuzhiyun VCAP_CONST_ACTION_WIDTH);
1313*4882a593Smuzhiyun /* The width of the counter memory, this is the complete width of all
1314*4882a593Smuzhiyun * counter-fields associated with one full-word entry. There is one
1315*4882a593Smuzhiyun * counter per entry sub-word (see CAP_CORE::ENTRY_SWCNT for number of
1316*4882a593Smuzhiyun * subwords.)
1317*4882a593Smuzhiyun */
1318*4882a593Smuzhiyun vcap->counter_words = vcap->sw_count;
1319*4882a593Smuzhiyun counter_memory_width = ocelot_target_read(ocelot, vcap->target,
1320*4882a593Smuzhiyun VCAP_CONST_CNT_WIDTH);
1321*4882a593Smuzhiyun vcap->counter_width = counter_memory_width / vcap->counter_words;
1322*4882a593Smuzhiyun }
1323*4882a593Smuzhiyun
ocelot_vcap_init(struct ocelot * ocelot)1324*4882a593Smuzhiyun int ocelot_vcap_init(struct ocelot *ocelot)
1325*4882a593Smuzhiyun {
1326*4882a593Smuzhiyun int i;
1327*4882a593Smuzhiyun
1328*4882a593Smuzhiyun /* Create a policer that will drop the frames for the cpu.
1329*4882a593Smuzhiyun * This policer will be used as action in the acl rules to drop
1330*4882a593Smuzhiyun * frames.
1331*4882a593Smuzhiyun */
1332*4882a593Smuzhiyun ocelot_write_gix(ocelot, 0x299, ANA_POL_MODE_CFG,
1333*4882a593Smuzhiyun OCELOT_POLICER_DISCARD);
1334*4882a593Smuzhiyun ocelot_write_gix(ocelot, 0x1, ANA_POL_PIR_CFG,
1335*4882a593Smuzhiyun OCELOT_POLICER_DISCARD);
1336*4882a593Smuzhiyun ocelot_write_gix(ocelot, 0x3fffff, ANA_POL_PIR_STATE,
1337*4882a593Smuzhiyun OCELOT_POLICER_DISCARD);
1338*4882a593Smuzhiyun ocelot_write_gix(ocelot, 0x0, ANA_POL_CIR_CFG,
1339*4882a593Smuzhiyun OCELOT_POLICER_DISCARD);
1340*4882a593Smuzhiyun ocelot_write_gix(ocelot, 0x3fffff, ANA_POL_CIR_STATE,
1341*4882a593Smuzhiyun OCELOT_POLICER_DISCARD);
1342*4882a593Smuzhiyun
1343*4882a593Smuzhiyun for (i = 0; i < OCELOT_NUM_VCAP_BLOCKS; i++) {
1344*4882a593Smuzhiyun struct ocelot_vcap_block *block = &ocelot->block[i];
1345*4882a593Smuzhiyun struct vcap_props *vcap = &ocelot->vcap[i];
1346*4882a593Smuzhiyun
1347*4882a593Smuzhiyun INIT_LIST_HEAD(&block->rules);
1348*4882a593Smuzhiyun block->pol_lpr = OCELOT_POLICER_DISCARD - 1;
1349*4882a593Smuzhiyun
1350*4882a593Smuzhiyun ocelot_vcap_detect_constants(ocelot, vcap);
1351*4882a593Smuzhiyun ocelot_vcap_init_one(ocelot, vcap);
1352*4882a593Smuzhiyun }
1353*4882a593Smuzhiyun
1354*4882a593Smuzhiyun INIT_LIST_HEAD(&ocelot->dummy_rules);
1355*4882a593Smuzhiyun
1356*4882a593Smuzhiyun return 0;
1357*4882a593Smuzhiyun }
1358