1 // SPDX-License-Identifier: (GPL-2.0 OR MIT)
2 /* Microsemi Ocelot Switch driver
3 * Copyright (c) 2019 Microsemi Corporation
6 #include <net/pkt_cls.h>
7 #include <net/tc_act/tc_gact.h>
9 #include "ocelot_ace.h"
11 struct ocelot_port_block
{
12 struct ocelot_acl_block
*block
;
13 struct ocelot_port
*port
;
16 static u16
get_prio(u32 prio
)
18 /* prio starts from 0x1000 while the ids starts from 0 */
22 static int ocelot_flower_parse_action(struct flow_cls_offload
*f
,
23 struct ocelot_ace_rule
*rule
)
25 const struct flow_action_entry
*a
;
28 if (f
->rule
->action
.num_entries
!= 1)
31 flow_action_for_each(i
, a
, &f
->rule
->action
) {
33 case FLOW_ACTION_DROP
:
34 rule
->action
= OCELOT_ACL_ACTION_DROP
;
36 case FLOW_ACTION_TRAP
:
37 rule
->action
= OCELOT_ACL_ACTION_TRAP
;
47 static int ocelot_flower_parse(struct flow_cls_offload
*f
,
48 struct ocelot_ace_rule
*ocelot_rule
)
50 struct flow_rule
*rule
= flow_cls_offload_flow_rule(f
);
51 struct flow_dissector
*dissector
= rule
->match
.dissector
;
53 if (dissector
->used_keys
&
54 ~(BIT(FLOW_DISSECTOR_KEY_CONTROL
) |
55 BIT(FLOW_DISSECTOR_KEY_BASIC
) |
56 BIT(FLOW_DISSECTOR_KEY_PORTS
) |
57 BIT(FLOW_DISSECTOR_KEY_VLAN
) |
58 BIT(FLOW_DISSECTOR_KEY_IPV4_ADDRS
) |
59 BIT(FLOW_DISSECTOR_KEY_IPV6_ADDRS
) |
60 BIT(FLOW_DISSECTOR_KEY_ETH_ADDRS
))) {
64 if (flow_rule_match_key(rule
, FLOW_DISSECTOR_KEY_CONTROL
)) {
65 struct flow_match_control match
;
67 flow_rule_match_control(rule
, &match
);
70 if (flow_rule_match_key(rule
, FLOW_DISSECTOR_KEY_ETH_ADDRS
)) {
71 struct flow_match_eth_addrs match
;
72 u16 proto
= ntohs(f
->common
.protocol
);
74 /* The hw support mac matches only for MAC_ETYPE key,
75 * therefore if other matches(port, tcp flags, etc) are added
78 if ((dissector
->used_keys
&
79 (BIT(FLOW_DISSECTOR_KEY_ETH_ADDRS
) |
80 BIT(FLOW_DISSECTOR_KEY_BASIC
) |
81 BIT(FLOW_DISSECTOR_KEY_CONTROL
))) !=
82 (BIT(FLOW_DISSECTOR_KEY_ETH_ADDRS
) |
83 BIT(FLOW_DISSECTOR_KEY_BASIC
) |
84 BIT(FLOW_DISSECTOR_KEY_CONTROL
)))
87 if (proto
== ETH_P_IP
||
88 proto
== ETH_P_IPV6
||
92 flow_rule_match_eth_addrs(rule
, &match
);
93 ocelot_rule
->type
= OCELOT_ACE_TYPE_ETYPE
;
94 ether_addr_copy(ocelot_rule
->frame
.etype
.dmac
.value
,
96 ether_addr_copy(ocelot_rule
->frame
.etype
.smac
.value
,
98 ether_addr_copy(ocelot_rule
->frame
.etype
.dmac
.mask
,
100 ether_addr_copy(ocelot_rule
->frame
.etype
.smac
.mask
,
102 goto finished_key_parsing
;
105 if (flow_rule_match_key(rule
, FLOW_DISSECTOR_KEY_BASIC
)) {
106 struct flow_match_basic match
;
108 flow_rule_match_basic(rule
, &match
);
109 if (ntohs(match
.key
->n_proto
) == ETH_P_IP
) {
110 ocelot_rule
->type
= OCELOT_ACE_TYPE_IPV4
;
111 ocelot_rule
->frame
.ipv4
.proto
.value
[0] =
113 ocelot_rule
->frame
.ipv4
.proto
.mask
[0] =
114 match
.mask
->ip_proto
;
116 if (ntohs(match
.key
->n_proto
) == ETH_P_IPV6
) {
117 ocelot_rule
->type
= OCELOT_ACE_TYPE_IPV6
;
118 ocelot_rule
->frame
.ipv6
.proto
.value
[0] =
120 ocelot_rule
->frame
.ipv6
.proto
.mask
[0] =
121 match
.mask
->ip_proto
;
125 if (flow_rule_match_key(rule
, FLOW_DISSECTOR_KEY_IPV4_ADDRS
) &&
126 ntohs(f
->common
.protocol
) == ETH_P_IP
) {
127 struct flow_match_ipv4_addrs match
;
130 flow_rule_match_ipv4_addrs(rule
, &match
);
131 tmp
= &ocelot_rule
->frame
.ipv4
.sip
.value
.addr
[0];
132 memcpy(tmp
, &match
.key
->src
, 4);
134 tmp
= &ocelot_rule
->frame
.ipv4
.sip
.mask
.addr
[0];
135 memcpy(tmp
, &match
.mask
->src
, 4);
137 tmp
= &ocelot_rule
->frame
.ipv4
.dip
.value
.addr
[0];
138 memcpy(tmp
, &match
.key
->dst
, 4);
140 tmp
= &ocelot_rule
->frame
.ipv4
.dip
.mask
.addr
[0];
141 memcpy(tmp
, &match
.mask
->dst
, 4);
144 if (flow_rule_match_key(rule
, FLOW_DISSECTOR_KEY_IPV6_ADDRS
) &&
145 ntohs(f
->common
.protocol
) == ETH_P_IPV6
) {
149 if (flow_rule_match_key(rule
, FLOW_DISSECTOR_KEY_PORTS
)) {
150 struct flow_match_ports match
;
152 flow_rule_match_ports(rule
, &match
);
153 ocelot_rule
->frame
.ipv4
.sport
.value
= ntohs(match
.key
->src
);
154 ocelot_rule
->frame
.ipv4
.sport
.mask
= ntohs(match
.mask
->src
);
155 ocelot_rule
->frame
.ipv4
.dport
.value
= ntohs(match
.key
->dst
);
156 ocelot_rule
->frame
.ipv4
.dport
.mask
= ntohs(match
.mask
->dst
);
159 if (flow_rule_match_key(rule
, FLOW_DISSECTOR_KEY_VLAN
)) {
160 struct flow_match_vlan match
;
162 flow_rule_match_vlan(rule
, &match
);
163 ocelot_rule
->type
= OCELOT_ACE_TYPE_ANY
;
164 ocelot_rule
->vlan
.vid
.value
= match
.key
->vlan_id
;
165 ocelot_rule
->vlan
.vid
.mask
= match
.mask
->vlan_id
;
166 ocelot_rule
->vlan
.pcp
.value
[0] = match
.key
->vlan_priority
;
167 ocelot_rule
->vlan
.pcp
.mask
[0] = match
.mask
->vlan_priority
;
170 finished_key_parsing
:
171 ocelot_rule
->prio
= get_prio(f
->common
.prio
);
172 ocelot_rule
->id
= f
->cookie
;
173 return ocelot_flower_parse_action(f
, ocelot_rule
);
177 struct ocelot_ace_rule
*ocelot_ace_rule_create(struct flow_cls_offload
*f
,
178 struct ocelot_port_block
*block
)
180 struct ocelot_ace_rule
*rule
;
182 rule
= kzalloc(sizeof(*rule
), GFP_KERNEL
);
186 rule
->port
= block
->port
;
187 rule
->chip_port
= block
->port
->chip_port
;
191 static int ocelot_flower_replace(struct flow_cls_offload
*f
,
192 struct ocelot_port_block
*port_block
)
194 struct ocelot_ace_rule
*rule
;
197 rule
= ocelot_ace_rule_create(f
, port_block
);
201 ret
= ocelot_flower_parse(f
, rule
);
207 ret
= ocelot_ace_rule_offload_add(rule
);
211 port_block
->port
->tc
.offload_cnt
++;
215 static int ocelot_flower_destroy(struct flow_cls_offload
*f
,
216 struct ocelot_port_block
*port_block
)
218 struct ocelot_ace_rule rule
;
221 rule
.prio
= get_prio(f
->common
.prio
);
222 rule
.port
= port_block
->port
;
225 ret
= ocelot_ace_rule_offload_del(&rule
);
229 port_block
->port
->tc
.offload_cnt
--;
233 static int ocelot_flower_stats_update(struct flow_cls_offload
*f
,
234 struct ocelot_port_block
*port_block
)
236 struct ocelot_ace_rule rule
;
239 rule
.prio
= get_prio(f
->common
.prio
);
240 rule
.port
= port_block
->port
;
242 ret
= ocelot_ace_rule_stats_update(&rule
);
246 flow_stats_update(&f
->stats
, 0x0, rule
.stats
.pkts
, 0x0);
250 static int ocelot_setup_tc_cls_flower(struct flow_cls_offload
*f
,
251 struct ocelot_port_block
*port_block
)
253 switch (f
->command
) {
254 case FLOW_CLS_REPLACE
:
255 return ocelot_flower_replace(f
, port_block
);
256 case FLOW_CLS_DESTROY
:
257 return ocelot_flower_destroy(f
, port_block
);
259 return ocelot_flower_stats_update(f
, port_block
);
265 static int ocelot_setup_tc_block_cb_flower(enum tc_setup_type type
,
266 void *type_data
, void *cb_priv
)
268 struct ocelot_port_block
*port_block
= cb_priv
;
270 if (!tc_cls_can_offload_and_chain0(port_block
->port
->dev
, type_data
))
274 case TC_SETUP_CLSFLOWER
:
275 return ocelot_setup_tc_cls_flower(type_data
, cb_priv
);
276 case TC_SETUP_CLSMATCHALL
:
283 static struct ocelot_port_block
*
284 ocelot_port_block_create(struct ocelot_port
*port
)
286 struct ocelot_port_block
*port_block
;
288 port_block
= kzalloc(sizeof(*port_block
), GFP_KERNEL
);
292 port_block
->port
= port
;
297 static void ocelot_port_block_destroy(struct ocelot_port_block
*block
)
302 static void ocelot_tc_block_unbind(void *cb_priv
)
304 struct ocelot_port_block
*port_block
= cb_priv
;
306 ocelot_port_block_destroy(port_block
);
309 int ocelot_setup_tc_block_flower_bind(struct ocelot_port
*port
,
310 struct flow_block_offload
*f
)
312 struct ocelot_port_block
*port_block
;
313 struct flow_block_cb
*block_cb
;
316 if (f
->binder_type
== FLOW_BLOCK_BINDER_TYPE_CLSACT_EGRESS
)
319 block_cb
= flow_block_cb_lookup(f
->block
,
320 ocelot_setup_tc_block_cb_flower
, port
);
322 port_block
= ocelot_port_block_create(port
);
326 block_cb
= flow_block_cb_alloc(ocelot_setup_tc_block_cb_flower
,
328 ocelot_tc_block_unbind
);
329 if (IS_ERR(block_cb
)) {
330 ret
= PTR_ERR(block_cb
);
331 goto err_cb_register
;
333 flow_block_cb_add(block_cb
, f
);
334 list_add_tail(&block_cb
->driver_list
, f
->driver_block_list
);
336 port_block
= flow_block_cb_priv(block_cb
);
339 flow_block_cb_incref(block_cb
);
343 ocelot_port_block_destroy(port_block
);
348 void ocelot_setup_tc_block_flower_unbind(struct ocelot_port
*port
,
349 struct flow_block_offload
*f
)
351 struct flow_block_cb
*block_cb
;
353 block_cb
= flow_block_cb_lookup(f
->block
,
354 ocelot_setup_tc_block_cb_flower
, port
);
358 if (!flow_block_cb_decref(block_cb
)) {
359 flow_block_cb_remove(block_cb
, f
);
360 list_del(&block_cb
->driver_list
);