1 // SPDX-License-Identifier: (GPL-2.0 OR MIT)
2 /* Microsemi Ocelot Switch TC driver
4 * Copyright (c) 2019 Microsemi Corporation
8 #include "ocelot_police.h"
9 #include "ocelot_ace.h"
10 #include <net/pkt_cls.h>
12 static int ocelot_setup_tc_cls_matchall(struct ocelot_port_private
*priv
,
13 struct tc_cls_matchall_offload
*f
,
16 struct netlink_ext_ack
*extack
= f
->common
.extack
;
17 struct ocelot
*ocelot
= priv
->port
.ocelot
;
18 struct ocelot_policer pol
= { 0 };
19 struct flow_action_entry
*action
;
20 int port
= priv
->chip_port
;
23 netdev_dbg(priv
->dev
, "%s: port %u command %d cookie %lu\n",
24 __func__
, port
, f
->command
, f
->cookie
);
27 NL_SET_ERR_MSG_MOD(extack
, "Only ingress is supported");
32 case TC_CLSMATCHALL_REPLACE
:
33 if (!flow_offload_has_one_action(&f
->rule
->action
)) {
34 NL_SET_ERR_MSG_MOD(extack
,
35 "Only one action is supported");
39 if (priv
->tc
.block_shared
) {
40 NL_SET_ERR_MSG_MOD(extack
,
41 "Rate limit is not supported on shared blocks");
45 action
= &f
->rule
->action
.entries
[0];
47 if (action
->id
!= FLOW_ACTION_POLICE
) {
48 NL_SET_ERR_MSG_MOD(extack
, "Unsupported action");
52 if (priv
->tc
.police_id
&& priv
->tc
.police_id
!= f
->cookie
) {
53 NL_SET_ERR_MSG_MOD(extack
,
54 "Only one policer per port is supported\n");
58 pol
.rate
= (u32
)div_u64(action
->police
.rate_bytes_ps
, 1000) * 8;
59 pol
.burst
= (u32
)div_u64(action
->police
.rate_bytes_ps
*
60 PSCHED_NS2TICKS(action
->police
.burst
),
61 PSCHED_TICKS_PER_SEC
);
63 err
= ocelot_port_policer_add(ocelot
, port
, &pol
);
65 NL_SET_ERR_MSG_MOD(extack
, "Could not add policer\n");
69 priv
->tc
.police_id
= f
->cookie
;
70 priv
->tc
.offload_cnt
++;
72 case TC_CLSMATCHALL_DESTROY
:
73 if (priv
->tc
.police_id
!= f
->cookie
)
76 err
= ocelot_port_policer_del(ocelot
, port
);
78 NL_SET_ERR_MSG_MOD(extack
,
79 "Could not delete policer\n");
82 priv
->tc
.police_id
= 0;
83 priv
->tc
.offload_cnt
--;
85 case TC_CLSMATCHALL_STATS
: /* fall through */
91 static int ocelot_setup_tc_block_cb(enum tc_setup_type type
,
93 void *cb_priv
, bool ingress
)
95 struct ocelot_port_private
*priv
= cb_priv
;
97 if (!tc_cls_can_offload_and_chain0(priv
->dev
, type_data
))
101 case TC_SETUP_CLSMATCHALL
:
102 netdev_dbg(priv
->dev
, "tc_block_cb: TC_SETUP_CLSMATCHALL %s\n",
103 ingress
? "ingress" : "egress");
105 return ocelot_setup_tc_cls_matchall(priv
, type_data
, ingress
);
106 case TC_SETUP_CLSFLOWER
:
109 netdev_dbg(priv
->dev
, "tc_block_cb: type %d %s\n",
111 ingress
? "ingress" : "egress");
117 static int ocelot_setup_tc_block_cb_ig(enum tc_setup_type type
,
121 return ocelot_setup_tc_block_cb(type
, type_data
,
125 static int ocelot_setup_tc_block_cb_eg(enum tc_setup_type type
,
129 return ocelot_setup_tc_block_cb(type
, type_data
,
133 static LIST_HEAD(ocelot_block_cb_list
);
135 static int ocelot_setup_tc_block(struct ocelot_port_private
*priv
,
136 struct flow_block_offload
*f
)
138 struct flow_block_cb
*block_cb
;
142 netdev_dbg(priv
->dev
, "tc_block command %d, binder_type %d\n",
143 f
->command
, f
->binder_type
);
145 if (f
->binder_type
== FLOW_BLOCK_BINDER_TYPE_CLSACT_INGRESS
) {
146 cb
= ocelot_setup_tc_block_cb_ig
;
147 priv
->tc
.block_shared
= f
->block_shared
;
148 } else if (f
->binder_type
== FLOW_BLOCK_BINDER_TYPE_CLSACT_EGRESS
) {
149 cb
= ocelot_setup_tc_block_cb_eg
;
154 f
->driver_block_list
= &ocelot_block_cb_list
;
156 switch (f
->command
) {
157 case FLOW_BLOCK_BIND
:
158 if (flow_block_cb_is_busy(cb
, priv
, &ocelot_block_cb_list
))
161 block_cb
= flow_block_cb_alloc(cb
, priv
, priv
, NULL
);
162 if (IS_ERR(block_cb
))
163 return PTR_ERR(block_cb
);
165 err
= ocelot_setup_tc_block_flower_bind(priv
, f
);
167 flow_block_cb_free(block_cb
);
170 flow_block_cb_add(block_cb
, f
);
171 list_add_tail(&block_cb
->driver_list
, f
->driver_block_list
);
173 case FLOW_BLOCK_UNBIND
:
174 block_cb
= flow_block_cb_lookup(f
->block
, cb
, priv
);
178 ocelot_setup_tc_block_flower_unbind(priv
, f
);
179 flow_block_cb_remove(block_cb
, f
);
180 list_del(&block_cb
->driver_list
);
187 int ocelot_setup_tc(struct net_device
*dev
, enum tc_setup_type type
,
190 struct ocelot_port_private
*priv
= netdev_priv(dev
);
194 return ocelot_setup_tc_block(priv
, type_data
);