xref: /linux/drivers/net/dsa/mv88e6xxx/tcflower.c (revision 0fc8f6200d2313278fbf4539bbab74677c685531)
1*639f1dcfSCedric Jehasse // SPDX-License-Identifier: GPL-2.0-or-later
2*639f1dcfSCedric Jehasse /*
3*639f1dcfSCedric Jehasse  * Marvell 88E6xxx Switch flower support
4*639f1dcfSCedric Jehasse  *
5*639f1dcfSCedric Jehasse  * Copyright (c) 2026 Luminex Network Intelligence
6*639f1dcfSCedric Jehasse  */
7*639f1dcfSCedric Jehasse 
8*639f1dcfSCedric Jehasse #include "chip.h"
9*639f1dcfSCedric Jehasse #include "tcflower.h"
10*639f1dcfSCedric Jehasse #include "tcam.h"
11*639f1dcfSCedric Jehasse 
12*639f1dcfSCedric Jehasse #define MV88E6XXX_ETHTYPE_OFFSET 16
13*639f1dcfSCedric Jehasse #define MV88E6XXX_IP_PROTO_OFFSET 27
14*639f1dcfSCedric Jehasse #define MV88E6XXX_IPV4_SRC_OFFSET 30
15*639f1dcfSCedric Jehasse #define MV88E6XXX_IPV4_DST_OFFSET 34
16*639f1dcfSCedric Jehasse 
17*639f1dcfSCedric Jehasse static int mv88e6xxx_flower_parse_key(struct mv88e6xxx_chip *chip,
18*639f1dcfSCedric Jehasse 				      struct netlink_ext_ack *extack,
19*639f1dcfSCedric Jehasse 				      struct flow_cls_offload *cls,
20*639f1dcfSCedric Jehasse 				      struct mv88e6xxx_tcam_key *key)
21*639f1dcfSCedric Jehasse {
22*639f1dcfSCedric Jehasse 	struct flow_rule *rule = flow_cls_offload_flow_rule(cls);
23*639f1dcfSCedric Jehasse 	struct flow_dissector *dissector = rule->match.dissector;
24*639f1dcfSCedric Jehasse 	u16 addr_type = 0;
25*639f1dcfSCedric Jehasse 
26*639f1dcfSCedric Jehasse 	if (dissector->used_keys &
27*639f1dcfSCedric Jehasse 	    ~(BIT_ULL(FLOW_DISSECTOR_KEY_BASIC) |
28*639f1dcfSCedric Jehasse 	      BIT_ULL(FLOW_DISSECTOR_KEY_CONTROL) |
29*639f1dcfSCedric Jehasse 	      BIT_ULL(FLOW_DISSECTOR_KEY_IPV4_ADDRS))) {
30*639f1dcfSCedric Jehasse 		NL_SET_ERR_MSG_MOD(extack,
31*639f1dcfSCedric Jehasse 				   "Unsupported keys used");
32*639f1dcfSCedric Jehasse 		return -EOPNOTSUPP;
33*639f1dcfSCedric Jehasse 	}
34*639f1dcfSCedric Jehasse 
35*639f1dcfSCedric Jehasse 	if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_CONTROL)) {
36*639f1dcfSCedric Jehasse 		struct flow_match_control match;
37*639f1dcfSCedric Jehasse 
38*639f1dcfSCedric Jehasse 		flow_rule_match_control(rule, &match);
39*639f1dcfSCedric Jehasse 		addr_type = match.key->addr_type;
40*639f1dcfSCedric Jehasse 
41*639f1dcfSCedric Jehasse 		if (flow_rule_has_control_flags(match.mask->flags,
42*639f1dcfSCedric Jehasse 						cls->common.extack))
43*639f1dcfSCedric Jehasse 			return -EOPNOTSUPP;
44*639f1dcfSCedric Jehasse 	}
45*639f1dcfSCedric Jehasse 	if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_BASIC)) {
46*639f1dcfSCedric Jehasse 		struct flow_match_basic match;
47*639f1dcfSCedric Jehasse 
48*639f1dcfSCedric Jehasse 		flow_rule_match_basic(rule, &match);
49*639f1dcfSCedric Jehasse 		mv88e6xxx_tcam_match_set(key, MV88E6XXX_ETHTYPE_OFFSET,
50*639f1dcfSCedric Jehasse 					 match.key->n_proto,
51*639f1dcfSCedric Jehasse 					 match.mask->n_proto);
52*639f1dcfSCedric Jehasse 		mv88e6xxx_tcam_match_set(key, MV88E6XXX_IP_PROTO_OFFSET,
53*639f1dcfSCedric Jehasse 					 match.key->ip_proto,
54*639f1dcfSCedric Jehasse 					 match.mask->ip_proto);
55*639f1dcfSCedric Jehasse 	}
56*639f1dcfSCedric Jehasse 
57*639f1dcfSCedric Jehasse 	if (addr_type == FLOW_DISSECTOR_KEY_IPV4_ADDRS) {
58*639f1dcfSCedric Jehasse 		struct flow_match_ipv4_addrs match;
59*639f1dcfSCedric Jehasse 
60*639f1dcfSCedric Jehasse 		flow_rule_match_ipv4_addrs(cls->rule, &match);
61*639f1dcfSCedric Jehasse 		mv88e6xxx_tcam_match_set(key, MV88E6XXX_IPV4_SRC_OFFSET,
62*639f1dcfSCedric Jehasse 					 match.key->src,
63*639f1dcfSCedric Jehasse 					 match.mask->src);
64*639f1dcfSCedric Jehasse 		mv88e6xxx_tcam_match_set(key, MV88E6XXX_IPV4_DST_OFFSET,
65*639f1dcfSCedric Jehasse 					 match.key->dst,
66*639f1dcfSCedric Jehasse 					 match.mask->dst);
67*639f1dcfSCedric Jehasse 	}
68*639f1dcfSCedric Jehasse 
69*639f1dcfSCedric Jehasse 	return 0;
70*639f1dcfSCedric Jehasse }
71*639f1dcfSCedric Jehasse 
72*639f1dcfSCedric Jehasse int mv88e6xxx_cls_flower_add(struct dsa_switch *ds, int port,
73*639f1dcfSCedric Jehasse 			     struct flow_cls_offload *cls, bool ingress)
74*639f1dcfSCedric Jehasse {
75*639f1dcfSCedric Jehasse 	struct flow_rule *rule = flow_cls_offload_flow_rule(cls);
76*639f1dcfSCedric Jehasse 	struct netlink_ext_ack *extack = cls->common.extack;
77*639f1dcfSCedric Jehasse 	struct mv88e6xxx_chip *chip = ds->priv;
78*639f1dcfSCedric Jehasse 	struct mv88e6xxx_tcam_key key = { 0 };
79*639f1dcfSCedric Jehasse 	const struct flow_action_entry *act;
80*639f1dcfSCedric Jehasse 	unsigned long cookie = cls->cookie;
81*639f1dcfSCedric Jehasse 	struct mv88e6xxx_tcam_entry *entry;
82*639f1dcfSCedric Jehasse 	int err, i;
83*639f1dcfSCedric Jehasse 
84*639f1dcfSCedric Jehasse 	if (!mv88e6xxx_has_tcam(chip)) {
85*639f1dcfSCedric Jehasse 		NL_SET_ERR_MSG_MOD(extack, "hardware offload not supported");
86*639f1dcfSCedric Jehasse 		return -EOPNOTSUPP;
87*639f1dcfSCedric Jehasse 	}
88*639f1dcfSCedric Jehasse 
89*639f1dcfSCedric Jehasse 	err = mv88e6xxx_flower_parse_key(chip, extack, cls, &key);
90*639f1dcfSCedric Jehasse 	if (err)
91*639f1dcfSCedric Jehasse 		return err;
92*639f1dcfSCedric Jehasse 
93*639f1dcfSCedric Jehasse 	mv88e6xxx_reg_lock(chip);
94*639f1dcfSCedric Jehasse 	entry = mv88e6xxx_tcam_entry_find(chip, cookie);
95*639f1dcfSCedric Jehasse 	if (entry) {
96*639f1dcfSCedric Jehasse 		err = -EEXIST;
97*639f1dcfSCedric Jehasse 		goto err_unlock;
98*639f1dcfSCedric Jehasse 	}
99*639f1dcfSCedric Jehasse 
100*639f1dcfSCedric Jehasse 	entry = kzalloc(sizeof(*entry), GFP_KERNEL);
101*639f1dcfSCedric Jehasse 	if (!entry) {
102*639f1dcfSCedric Jehasse 		err = -ENOMEM;
103*639f1dcfSCedric Jehasse 		goto err_unlock;
104*639f1dcfSCedric Jehasse 	}
105*639f1dcfSCedric Jehasse 
106*639f1dcfSCedric Jehasse 	entry->cookie = cookie;
107*639f1dcfSCedric Jehasse 	entry->prio = cls->common.prio;
108*639f1dcfSCedric Jehasse 	entry->key = key;
109*639f1dcfSCedric Jehasse 
110*639f1dcfSCedric Jehasse 	flow_action_for_each(i, act, &rule->action) {
111*639f1dcfSCedric Jehasse 		switch (act->id) {
112*639f1dcfSCedric Jehasse 		case FLOW_ACTION_TRAP: {
113*639f1dcfSCedric Jehasse 			int cpu = dsa_upstream_port(ds, port);
114*639f1dcfSCedric Jehasse 
115*639f1dcfSCedric Jehasse 			entry->action.dpv_mode = DPV_MODE_REPLACE;
116*639f1dcfSCedric Jehasse 			entry->action.dpv = BIT(cpu);
117*639f1dcfSCedric Jehasse 			break;
118*639f1dcfSCedric Jehasse 		}
119*639f1dcfSCedric Jehasse 		default:
120*639f1dcfSCedric Jehasse 			NL_SET_ERR_MSG_MOD(extack, "action not supported");
121*639f1dcfSCedric Jehasse 			err = -EOPNOTSUPP;
122*639f1dcfSCedric Jehasse 			goto err_free_entry;
123*639f1dcfSCedric Jehasse 		}
124*639f1dcfSCedric Jehasse 	}
125*639f1dcfSCedric Jehasse 
126*639f1dcfSCedric Jehasse 	entry->key.spv = BIT(port);
127*639f1dcfSCedric Jehasse 	entry->key.spv_mask = mv88e6xxx_port_mask(chip);
128*639f1dcfSCedric Jehasse 
129*639f1dcfSCedric Jehasse 	err = mv88e6xxx_tcam_entry_add(chip, entry);
130*639f1dcfSCedric Jehasse 	if (err)
131*639f1dcfSCedric Jehasse 		goto err_free_entry;
132*639f1dcfSCedric Jehasse 
133*639f1dcfSCedric Jehasse 	mv88e6xxx_reg_unlock(chip);
134*639f1dcfSCedric Jehasse 	return  0;
135*639f1dcfSCedric Jehasse 
136*639f1dcfSCedric Jehasse err_free_entry:
137*639f1dcfSCedric Jehasse 	kfree(entry);
138*639f1dcfSCedric Jehasse err_unlock:
139*639f1dcfSCedric Jehasse 	mv88e6xxx_reg_unlock(chip);
140*639f1dcfSCedric Jehasse 	return err;
141*639f1dcfSCedric Jehasse }
142*639f1dcfSCedric Jehasse 
143*639f1dcfSCedric Jehasse int mv88e6xxx_cls_flower_del(struct dsa_switch *ds, int port,
144*639f1dcfSCedric Jehasse 			     struct flow_cls_offload *cls, bool ingress)
145*639f1dcfSCedric Jehasse {
146*639f1dcfSCedric Jehasse 	struct mv88e6xxx_chip *chip = ds->priv;
147*639f1dcfSCedric Jehasse 	struct mv88e6xxx_tcam_entry *entry;
148*639f1dcfSCedric Jehasse 	int err = 0;
149*639f1dcfSCedric Jehasse 
150*639f1dcfSCedric Jehasse 	mv88e6xxx_reg_lock(chip);
151*639f1dcfSCedric Jehasse 	entry = mv88e6xxx_tcam_entry_find(chip, cls->cookie);
152*639f1dcfSCedric Jehasse 
153*639f1dcfSCedric Jehasse 	if (entry)
154*639f1dcfSCedric Jehasse 		err = mv88e6xxx_tcam_entry_del(chip, entry);
155*639f1dcfSCedric Jehasse 	mv88e6xxx_reg_unlock(chip);
156*639f1dcfSCedric Jehasse 	return  err;
157*639f1dcfSCedric Jehasse }
158*639f1dcfSCedric Jehasse 
159*639f1dcfSCedric Jehasse void mv88e6xxx_flower_teardown(struct mv88e6xxx_chip *chip)
160*639f1dcfSCedric Jehasse {
161*639f1dcfSCedric Jehasse 	struct mv88e6xxx_tcam_entry *pos, *n;
162*639f1dcfSCedric Jehasse 
163*639f1dcfSCedric Jehasse 	list_for_each_entry_safe(pos, n, &chip->tcam.entries, list) {
164*639f1dcfSCedric Jehasse 		list_del(&pos->list);
165*639f1dcfSCedric Jehasse 		kfree(pos);
166*639f1dcfSCedric Jehasse 	}
167*639f1dcfSCedric Jehasse }
168