1 // SPDX-License-Identifier: (GPL-2.0 OR MIT)
3 * Copyright (c) 2018 Synopsys, Inc. and/or its affiliates.
4 * stmmac TC Handling (HW only)
7 #include <net/pkt_cls.h>
8 #include <net/tc_act/tc_gact.h>
14 static void tc_fill_all_pass_entry(struct stmmac_tc_entry
*entry
)
16 memset(entry
, 0, sizeof(*entry
));
18 entry
->is_last
= true;
19 entry
->is_frag
= false;
22 entry
->val
.match_data
= 0x0;
23 entry
->val
.match_en
= 0x0;
25 entry
->val
.dma_ch_no
= 0x0;
28 static struct stmmac_tc_entry
*tc_find_entry(struct stmmac_priv
*priv
,
29 struct tc_cls_u32_offload
*cls
,
32 struct stmmac_tc_entry
*entry
, *first
= NULL
, *dup
= NULL
;
33 u32 loc
= cls
->knode
.handle
;
36 for (i
= 0; i
< priv
->tc_entries_max
; i
++) {
37 entry
= &priv
->tc_entries
[i
];
38 if (!entry
->in_use
&& !first
&& free
)
40 if (entry
->handle
== loc
&& !free
)
51 memset(&first
->val
, 0, sizeof(first
->val
));
57 static int tc_fill_actions(struct stmmac_tc_entry
*entry
,
58 struct stmmac_tc_entry
*frag
,
59 struct tc_cls_u32_offload
*cls
)
61 struct stmmac_tc_entry
*action_entry
= entry
;
62 const struct tc_action
*act
;
63 struct tcf_exts
*exts
;
66 exts
= cls
->knode
.exts
;
67 if (!tcf_exts_has_actions(exts
))
72 tcf_exts_to_list(exts
, &actions
);
73 list_for_each_entry(act
, &actions
, list
) {
75 if (is_tcf_gact_ok(act
)) {
76 action_entry
->val
.af
= 1;
80 if (is_tcf_gact_shot(act
)) {
81 action_entry
->val
.rf
= 1;
92 static int tc_fill_entry(struct stmmac_priv
*priv
,
93 struct tc_cls_u32_offload
*cls
)
95 struct stmmac_tc_entry
*entry
, *frag
= NULL
;
96 struct tc_u32_sel
*sel
= cls
->knode
.sel
;
97 u32 off
, data
, mask
, real_off
, rem
;
98 u32 prio
= cls
->common
.prio
;
101 /* Only 1 match per entry */
102 if (sel
->nkeys
<= 0 || sel
->nkeys
> 1)
105 off
= sel
->keys
[0].off
<< sel
->offshift
;
106 data
= sel
->keys
[0].val
;
107 mask
= sel
->keys
[0].mask
;
109 switch (ntohs(cls
->common
.protocol
)) {
119 if (off
> priv
->tc_off_max
)
125 entry
= tc_find_entry(priv
, cls
, true);
130 frag
= tc_find_entry(priv
, cls
, true);
136 entry
->frag_ptr
= frag
;
137 entry
->val
.match_en
= (mask
<< (rem
* 8)) &
138 GENMASK(31, rem
* 8);
139 entry
->val
.match_data
= (data
<< (rem
* 8)) &
140 GENMASK(31, rem
* 8);
141 entry
->val
.frame_offset
= real_off
;
144 frag
->val
.match_en
= (mask
>> (rem
* 8)) &
145 GENMASK(rem
* 8 - 1, 0);
146 frag
->val
.match_data
= (data
>> (rem
* 8)) &
147 GENMASK(rem
* 8 - 1, 0);
148 frag
->val
.frame_offset
= real_off
+ 1;
150 frag
->is_frag
= true;
152 entry
->frag_ptr
= NULL
;
153 entry
->val
.match_en
= mask
;
154 entry
->val
.match_data
= data
;
155 entry
->val
.frame_offset
= real_off
;
159 ret
= tc_fill_actions(entry
, frag
, cls
);
167 frag
->in_use
= false;
168 entry
->in_use
= false;
172 static void tc_unfill_entry(struct stmmac_priv
*priv
,
173 struct tc_cls_u32_offload
*cls
)
175 struct stmmac_tc_entry
*entry
;
177 entry
= tc_find_entry(priv
, cls
, false);
181 entry
->in_use
= false;
182 if (entry
->frag_ptr
) {
183 entry
= entry
->frag_ptr
;
184 entry
->is_frag
= false;
185 entry
->in_use
= false;
189 static int tc_config_knode(struct stmmac_priv
*priv
,
190 struct tc_cls_u32_offload
*cls
)
194 ret
= tc_fill_entry(priv
, cls
);
198 ret
= stmmac_rxp_config(priv
, priv
->hw
->pcsr
, priv
->tc_entries
,
199 priv
->tc_entries_max
);
206 tc_unfill_entry(priv
, cls
);
210 static int tc_delete_knode(struct stmmac_priv
*priv
,
211 struct tc_cls_u32_offload
*cls
)
215 /* Set entry and fragments as not used */
216 tc_unfill_entry(priv
, cls
);
218 ret
= stmmac_rxp_config(priv
, priv
->hw
->pcsr
, priv
->tc_entries
,
219 priv
->tc_entries_max
);
226 static int tc_setup_cls_u32(struct stmmac_priv
*priv
,
227 struct tc_cls_u32_offload
*cls
)
229 switch (cls
->command
) {
230 case TC_CLSU32_REPLACE_KNODE
:
231 tc_unfill_entry(priv
, cls
);
233 case TC_CLSU32_NEW_KNODE
:
234 return tc_config_knode(priv
, cls
);
235 case TC_CLSU32_DELETE_KNODE
:
236 return tc_delete_knode(priv
, cls
);
242 static int tc_init(struct stmmac_priv
*priv
)
244 struct dma_features
*dma_cap
= &priv
->dma_cap
;
247 if (!dma_cap
->frpsel
)
250 switch (dma_cap
->frpbs
) {
252 priv
->tc_off_max
= 64;
255 priv
->tc_off_max
= 128;
258 priv
->tc_off_max
= 256;
264 switch (dma_cap
->frpes
) {
278 /* Reserve one last filter which lets all pass */
279 priv
->tc_entries_max
= count
;
280 priv
->tc_entries
= devm_kcalloc(priv
->device
,
281 count
, sizeof(*priv
->tc_entries
), GFP_KERNEL
);
282 if (!priv
->tc_entries
)
285 tc_fill_all_pass_entry(&priv
->tc_entries
[count
- 1]);
287 dev_info(priv
->device
, "Enabling HW TC (entries=%d, max_off=%d)\n",
288 priv
->tc_entries_max
, priv
->tc_off_max
);
292 const struct stmmac_tc_ops dwmac510_tc_ops
= {
294 .setup_cls_u32
= tc_setup_cls_u32
,