gpio: rcar: Fix runtime PM imbalance on error
[linux/fpc-iii.git] / drivers / net / ethernet / mscc / ocelot_flower.c
blob341923311fec3ad783efa929cdd0cabe481d85aa
1 // SPDX-License-Identifier: (GPL-2.0 OR MIT)
2 /* Microsemi Ocelot Switch driver
3 * Copyright (c) 2019 Microsemi Corporation
4 */
6 #include <net/pkt_cls.h>
7 #include <net/tc_act/tc_gact.h>
9 #include "ocelot_ace.h"
11 static int ocelot_flower_parse_action(struct flow_cls_offload *f,
12 struct ocelot_ace_rule *ace)
14 const struct flow_action_entry *a;
15 s64 burst;
16 u64 rate;
17 int i;
19 if (!flow_offload_has_one_action(&f->rule->action))
20 return -EOPNOTSUPP;
22 if (!flow_action_basic_hw_stats_check(&f->rule->action,
23 f->common.extack))
24 return -EOPNOTSUPP;
26 flow_action_for_each(i, a, &f->rule->action) {
27 switch (a->id) {
28 case FLOW_ACTION_DROP:
29 ace->action = OCELOT_ACL_ACTION_DROP;
30 break;
31 case FLOW_ACTION_TRAP:
32 ace->action = OCELOT_ACL_ACTION_TRAP;
33 break;
34 case FLOW_ACTION_POLICE:
35 ace->action = OCELOT_ACL_ACTION_POLICE;
36 rate = a->police.rate_bytes_ps;
37 ace->pol.rate = div_u64(rate, 1000) * 8;
38 burst = rate * PSCHED_NS2TICKS(a->police.burst);
39 ace->pol.burst = div_u64(burst, PSCHED_TICKS_PER_SEC);
40 break;
41 default:
42 return -EOPNOTSUPP;
46 return 0;
49 static int ocelot_flower_parse(struct flow_cls_offload *f,
50 struct ocelot_ace_rule *ace)
52 struct flow_rule *rule = flow_cls_offload_flow_rule(f);
53 struct flow_dissector *dissector = rule->match.dissector;
55 if (dissector->used_keys &
56 ~(BIT(FLOW_DISSECTOR_KEY_CONTROL) |
57 BIT(FLOW_DISSECTOR_KEY_BASIC) |
58 BIT(FLOW_DISSECTOR_KEY_PORTS) |
59 BIT(FLOW_DISSECTOR_KEY_VLAN) |
60 BIT(FLOW_DISSECTOR_KEY_IPV4_ADDRS) |
61 BIT(FLOW_DISSECTOR_KEY_IPV6_ADDRS) |
62 BIT(FLOW_DISSECTOR_KEY_ETH_ADDRS))) {
63 return -EOPNOTSUPP;
66 if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_CONTROL)) {
67 struct flow_match_control match;
69 flow_rule_match_control(rule, &match);
72 if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_ETH_ADDRS)) {
73 struct flow_match_eth_addrs match;
74 u16 proto = ntohs(f->common.protocol);
76 /* The hw support mac matches only for MAC_ETYPE key,
77 * therefore if other matches(port, tcp flags, etc) are added
78 * then just bail out
80 if ((dissector->used_keys &
81 (BIT(FLOW_DISSECTOR_KEY_ETH_ADDRS) |
82 BIT(FLOW_DISSECTOR_KEY_BASIC) |
83 BIT(FLOW_DISSECTOR_KEY_CONTROL))) !=
84 (BIT(FLOW_DISSECTOR_KEY_ETH_ADDRS) |
85 BIT(FLOW_DISSECTOR_KEY_BASIC) |
86 BIT(FLOW_DISSECTOR_KEY_CONTROL)))
87 return -EOPNOTSUPP;
89 if (proto == ETH_P_IP ||
90 proto == ETH_P_IPV6 ||
91 proto == ETH_P_ARP)
92 return -EOPNOTSUPP;
94 flow_rule_match_eth_addrs(rule, &match);
95 ace->type = OCELOT_ACE_TYPE_ETYPE;
96 ether_addr_copy(ace->frame.etype.dmac.value,
97 match.key->dst);
98 ether_addr_copy(ace->frame.etype.smac.value,
99 match.key->src);
100 ether_addr_copy(ace->frame.etype.dmac.mask,
101 match.mask->dst);
102 ether_addr_copy(ace->frame.etype.smac.mask,
103 match.mask->src);
104 goto finished_key_parsing;
107 if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_BASIC)) {
108 struct flow_match_basic match;
110 flow_rule_match_basic(rule, &match);
111 if (ntohs(match.key->n_proto) == ETH_P_IP) {
112 ace->type = OCELOT_ACE_TYPE_IPV4;
113 ace->frame.ipv4.proto.value[0] =
114 match.key->ip_proto;
115 ace->frame.ipv4.proto.mask[0] =
116 match.mask->ip_proto;
118 if (ntohs(match.key->n_proto) == ETH_P_IPV6) {
119 ace->type = OCELOT_ACE_TYPE_IPV6;
120 ace->frame.ipv6.proto.value[0] =
121 match.key->ip_proto;
122 ace->frame.ipv6.proto.mask[0] =
123 match.mask->ip_proto;
127 if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_IPV4_ADDRS) &&
128 ntohs(f->common.protocol) == ETH_P_IP) {
129 struct flow_match_ipv4_addrs match;
130 u8 *tmp;
132 flow_rule_match_ipv4_addrs(rule, &match);
133 tmp = &ace->frame.ipv4.sip.value.addr[0];
134 memcpy(tmp, &match.key->src, 4);
136 tmp = &ace->frame.ipv4.sip.mask.addr[0];
137 memcpy(tmp, &match.mask->src, 4);
139 tmp = &ace->frame.ipv4.dip.value.addr[0];
140 memcpy(tmp, &match.key->dst, 4);
142 tmp = &ace->frame.ipv4.dip.mask.addr[0];
143 memcpy(tmp, &match.mask->dst, 4);
146 if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_IPV6_ADDRS) &&
147 ntohs(f->common.protocol) == ETH_P_IPV6) {
148 return -EOPNOTSUPP;
151 if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_PORTS)) {
152 struct flow_match_ports match;
154 flow_rule_match_ports(rule, &match);
155 ace->frame.ipv4.sport.value = ntohs(match.key->src);
156 ace->frame.ipv4.sport.mask = ntohs(match.mask->src);
157 ace->frame.ipv4.dport.value = ntohs(match.key->dst);
158 ace->frame.ipv4.dport.mask = ntohs(match.mask->dst);
161 if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_VLAN)) {
162 struct flow_match_vlan match;
164 flow_rule_match_vlan(rule, &match);
165 ace->type = OCELOT_ACE_TYPE_ANY;
166 ace->vlan.vid.value = match.key->vlan_id;
167 ace->vlan.vid.mask = match.mask->vlan_id;
168 ace->vlan.pcp.value[0] = match.key->vlan_priority;
169 ace->vlan.pcp.mask[0] = match.mask->vlan_priority;
172 finished_key_parsing:
173 ace->prio = f->common.prio;
174 ace->id = f->cookie;
175 return ocelot_flower_parse_action(f, ace);
178 static
179 struct ocelot_ace_rule *ocelot_ace_rule_create(struct ocelot *ocelot, int port,
180 struct flow_cls_offload *f)
182 struct ocelot_ace_rule *ace;
184 ace = kzalloc(sizeof(*ace), GFP_KERNEL);
185 if (!ace)
186 return NULL;
188 ace->ingress_port_mask = BIT(port);
189 return ace;
192 int ocelot_cls_flower_replace(struct ocelot *ocelot, int port,
193 struct flow_cls_offload *f, bool ingress)
195 struct ocelot_ace_rule *ace;
196 int ret;
198 ace = ocelot_ace_rule_create(ocelot, port, f);
199 if (!ace)
200 return -ENOMEM;
202 ret = ocelot_flower_parse(f, ace);
203 if (ret) {
204 kfree(ace);
205 return ret;
208 return ocelot_ace_rule_offload_add(ocelot, ace);
210 EXPORT_SYMBOL_GPL(ocelot_cls_flower_replace);
212 int ocelot_cls_flower_destroy(struct ocelot *ocelot, int port,
213 struct flow_cls_offload *f, bool ingress)
215 struct ocelot_ace_rule ace;
217 ace.prio = f->common.prio;
218 ace.id = f->cookie;
220 return ocelot_ace_rule_offload_del(ocelot, &ace);
222 EXPORT_SYMBOL_GPL(ocelot_cls_flower_destroy);
224 int ocelot_cls_flower_stats(struct ocelot *ocelot, int port,
225 struct flow_cls_offload *f, bool ingress)
227 struct ocelot_ace_rule ace;
228 int ret;
230 ace.prio = f->common.prio;
231 ace.id = f->cookie;
232 ret = ocelot_ace_rule_stats_update(ocelot, &ace);
233 if (ret)
234 return ret;
236 flow_stats_update(&f->stats, 0x0, ace.stats.pkts, 0x0,
237 FLOW_ACTION_HW_STATS_IMMEDIATE);
238 return 0;
240 EXPORT_SYMBOL_GPL(ocelot_cls_flower_stats);
242 int ocelot_setup_tc_cls_flower(struct ocelot_port_private *priv,
243 struct flow_cls_offload *f,
244 bool ingress)
246 struct ocelot *ocelot = priv->port.ocelot;
247 int port = priv->chip_port;
249 if (!ingress)
250 return -EOPNOTSUPP;
252 switch (f->command) {
253 case FLOW_CLS_REPLACE:
254 return ocelot_cls_flower_replace(ocelot, port, f, ingress);
255 case FLOW_CLS_DESTROY:
256 return ocelot_cls_flower_destroy(ocelot, port, f, ingress);
257 case FLOW_CLS_STATS:
258 return ocelot_cls_flower_stats(ocelot, port, f, ingress);
259 default:
260 return -EOPNOTSUPP;