1 // SPDX-License-Identifier: (GPL-2.0 OR MIT)
2 /* Microsemi Ocelot Switch TC driver
4 * Copyright (c) 2019 Microsemi Corporation
7 #include <soc/mscc/ocelot.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
;
24 NL_SET_ERR_MSG_MOD(extack
, "Only ingress is supported");
29 case TC_CLSMATCHALL_REPLACE
:
30 if (!flow_offload_has_one_action(&f
->rule
->action
)) {
31 NL_SET_ERR_MSG_MOD(extack
,
32 "Only one action is supported");
36 if (priv
->tc
.block_shared
) {
37 NL_SET_ERR_MSG_MOD(extack
,
38 "Rate limit is not supported on shared blocks");
42 action
= &f
->rule
->action
.entries
[0];
44 if (action
->id
!= FLOW_ACTION_POLICE
) {
45 NL_SET_ERR_MSG_MOD(extack
, "Unsupported action");
49 if (priv
->tc
.police_id
&& priv
->tc
.police_id
!= f
->cookie
) {
50 NL_SET_ERR_MSG_MOD(extack
,
51 "Only one policer per port is supported\n");
55 pol
.rate
= (u32
)div_u64(action
->police
.rate_bytes_ps
, 1000) * 8;
56 pol
.burst
= (u32
)div_u64(action
->police
.rate_bytes_ps
*
57 PSCHED_NS2TICKS(action
->police
.burst
),
58 PSCHED_TICKS_PER_SEC
);
60 err
= ocelot_port_policer_add(ocelot
, port
, &pol
);
62 NL_SET_ERR_MSG_MOD(extack
, "Could not add policer\n");
66 priv
->tc
.police_id
= f
->cookie
;
67 priv
->tc
.offload_cnt
++;
69 case TC_CLSMATCHALL_DESTROY
:
70 if (priv
->tc
.police_id
!= f
->cookie
)
73 err
= ocelot_port_policer_del(ocelot
, port
);
75 NL_SET_ERR_MSG_MOD(extack
,
76 "Could not delete policer\n");
79 priv
->tc
.police_id
= 0;
80 priv
->tc
.offload_cnt
--;
82 case TC_CLSMATCHALL_STATS
: /* fall through */
88 static int ocelot_setup_tc_block_cb(enum tc_setup_type type
,
90 void *cb_priv
, bool ingress
)
92 struct ocelot_port_private
*priv
= cb_priv
;
94 if (!tc_cls_can_offload_and_chain0(priv
->dev
, type_data
))
98 case TC_SETUP_CLSMATCHALL
:
99 return ocelot_setup_tc_cls_matchall(priv
, type_data
, ingress
);
100 case TC_SETUP_CLSFLOWER
:
101 return ocelot_setup_tc_cls_flower(priv
, type_data
, ingress
);
107 static int ocelot_setup_tc_block_cb_ig(enum tc_setup_type type
,
111 return ocelot_setup_tc_block_cb(type
, type_data
,
115 static int ocelot_setup_tc_block_cb_eg(enum tc_setup_type type
,
119 return ocelot_setup_tc_block_cb(type
, type_data
,
123 static LIST_HEAD(ocelot_block_cb_list
);
125 static int ocelot_setup_tc_block(struct ocelot_port_private
*priv
,
126 struct flow_block_offload
*f
)
128 struct flow_block_cb
*block_cb
;
131 if (f
->binder_type
== FLOW_BLOCK_BINDER_TYPE_CLSACT_INGRESS
) {
132 cb
= ocelot_setup_tc_block_cb_ig
;
133 priv
->tc
.block_shared
= f
->block_shared
;
134 } else if (f
->binder_type
== FLOW_BLOCK_BINDER_TYPE_CLSACT_EGRESS
) {
135 cb
= ocelot_setup_tc_block_cb_eg
;
140 f
->driver_block_list
= &ocelot_block_cb_list
;
142 switch (f
->command
) {
143 case FLOW_BLOCK_BIND
:
144 if (flow_block_cb_is_busy(cb
, priv
, &ocelot_block_cb_list
))
147 block_cb
= flow_block_cb_alloc(cb
, priv
, priv
, NULL
);
148 if (IS_ERR(block_cb
))
149 return PTR_ERR(block_cb
);
151 flow_block_cb_add(block_cb
, f
);
152 list_add_tail(&block_cb
->driver_list
, f
->driver_block_list
);
154 case FLOW_BLOCK_UNBIND
:
155 block_cb
= flow_block_cb_lookup(f
->block
, cb
, priv
);
159 flow_block_cb_remove(block_cb
, f
);
160 list_del(&block_cb
->driver_list
);
167 int ocelot_setup_tc(struct net_device
*dev
, enum tc_setup_type type
,
170 struct ocelot_port_private
*priv
= netdev_priv(dev
);
174 return ocelot_setup_tc_block(priv
, type_data
);