Linux Audio

Check our new training course

Loading...
Note: File does not exist in v5.4.
  1// SPDX-License-Identifier: GPL-2.0+
  2/* Microchip VCAP API
  3 *
  4 * Copyright (c) 2022 Microchip Technology Inc. and its subsidiaries.
  5 */
  6
  7#include "sparx5_tc.h"
  8#include "vcap_api.h"
  9#include "vcap_api_client.h"
 10#include "sparx5_main_regs.h"
 11#include "sparx5_main.h"
 12#include "sparx5_vcap_impl.h"
 13
 14static struct sparx5_mall_entry *
 15sparx5_tc_matchall_entry_find(struct list_head *entries, unsigned long cookie)
 16{
 17	struct sparx5_mall_entry *entry;
 18
 19	list_for_each_entry(entry, entries, list) {
 20		if (entry->cookie == cookie)
 21			return entry;
 22	}
 23
 24	return NULL;
 25}
 26
 27static void sparx5_tc_matchall_parse_action(struct sparx5_port *port,
 28					    struct sparx5_mall_entry *entry,
 29					    struct flow_action_entry *action,
 30					    bool ingress,
 31					    unsigned long cookie)
 32{
 33	entry->port = port;
 34	entry->type = action->id;
 35	entry->ingress = ingress;
 36	entry->cookie = cookie;
 37}
 38
 39static void
 40sparx5_tc_matchall_parse_mirror_action(struct sparx5_mall_entry *entry,
 41				       struct flow_action_entry *action)
 42{
 43	entry->mirror.port = netdev_priv(action->dev);
 44}
 45
 46static int sparx5_tc_matchall_replace(struct net_device *ndev,
 47				      struct tc_cls_matchall_offload *tmo,
 48				      bool ingress)
 49{
 50	struct sparx5_port *port = netdev_priv(ndev);
 51	struct sparx5_mall_entry *mall_entry;
 52	struct flow_action_entry *action;
 53	struct sparx5 *sparx5;
 54	int err;
 55
 56	if (!flow_offload_has_one_action(&tmo->rule->action)) {
 57		NL_SET_ERR_MSG_MOD(tmo->common.extack,
 58				   "Only one action per filter is supported");
 59		return -EOPNOTSUPP;
 60	}
 61	action = &tmo->rule->action.entries[0];
 62
 63	mall_entry = kzalloc(sizeof(*mall_entry), GFP_KERNEL);
 64	if (!mall_entry)
 65		return -ENOMEM;
 66
 67	sparx5_tc_matchall_parse_action(port,
 68					mall_entry,
 69					action,
 70					ingress,
 71					tmo->cookie);
 72
 73	sparx5 = port->sparx5;
 74	switch (action->id) {
 75	case FLOW_ACTION_MIRRED:
 76		sparx5_tc_matchall_parse_mirror_action(mall_entry, action);
 77		err = sparx5_mirror_add(mall_entry);
 78		if (err) {
 79			switch (err) {
 80			case -EEXIST:
 81				NL_SET_ERR_MSG_MOD(tmo->common.extack,
 82						   "Mirroring already exists");
 83				break;
 84			case -EINVAL:
 85				NL_SET_ERR_MSG_MOD(tmo->common.extack,
 86						   "Cannot mirror a monitor port");
 87				break;
 88			case -ENOENT:
 89				NL_SET_ERR_MSG_MOD(tmo->common.extack,
 90						   "No more mirror probes available");
 91				break;
 92			default:
 93				NL_SET_ERR_MSG_MOD(tmo->common.extack,
 94						   "Unknown error");
 95				break;
 96			}
 97			return err;
 98		}
 99		/* Get baseline stats for this port */
100		sparx5_mirror_stats(mall_entry, &tmo->stats);
101		break;
102	case FLOW_ACTION_GOTO:
103		err = vcap_enable_lookups(sparx5->vcap_ctrl, ndev,
104					  tmo->common.chain_index,
105					  action->chain_index, tmo->cookie,
106					  true);
107		if (err == -EFAULT) {
108			NL_SET_ERR_MSG_MOD(tmo->common.extack,
109					   "Unsupported goto chain");
110			return -EOPNOTSUPP;
111		}
112		if (err == -EADDRINUSE) {
113			NL_SET_ERR_MSG_MOD(tmo->common.extack,
114					   "VCAP already enabled");
115			return -EOPNOTSUPP;
116		}
117		if (err == -EADDRNOTAVAIL) {
118			NL_SET_ERR_MSG_MOD(tmo->common.extack,
119					   "Already matching this chain");
120			return -EOPNOTSUPP;
121		}
122		if (err) {
123			NL_SET_ERR_MSG_MOD(tmo->common.extack,
124					   "Could not enable VCAP lookups");
125			return err;
126		}
127		break;
128	default:
129		NL_SET_ERR_MSG_MOD(tmo->common.extack, "Unsupported action");
130		return -EOPNOTSUPP;
131	}
132
133	list_add_tail(&mall_entry->list, &sparx5->mall_entries);
134
135	return 0;
136}
137
138static int sparx5_tc_matchall_destroy(struct net_device *ndev,
139				      struct tc_cls_matchall_offload *tmo,
140				      bool ingress)
141{
142	struct sparx5_port *port = netdev_priv(ndev);
143	struct sparx5 *sparx5 = port->sparx5;
144	struct sparx5_mall_entry *entry;
145	int err = 0;
146
147	entry = sparx5_tc_matchall_entry_find(&sparx5->mall_entries,
148					      tmo->cookie);
149	if (!entry)
150		return -ENOENT;
151
152	if (entry->type == FLOW_ACTION_MIRRED) {
153		sparx5_mirror_del(entry);
154	} else if (entry->type == FLOW_ACTION_GOTO) {
155		err = vcap_enable_lookups(sparx5->vcap_ctrl, ndev,
156					  0, 0, tmo->cookie, false);
157	} else {
158		NL_SET_ERR_MSG_MOD(tmo->common.extack, "Unsupported action");
159		err = -EOPNOTSUPP;
160	}
161
162	list_del(&entry->list);
163
164	return err;
165}
166
167static int sparx5_tc_matchall_stats(struct net_device *ndev,
168				    struct tc_cls_matchall_offload *tmo,
169				    bool ingress)
170{
171	struct sparx5_port *port = netdev_priv(ndev);
172	struct sparx5 *sparx5 = port->sparx5;
173	struct sparx5_mall_entry *entry;
174
175	entry = sparx5_tc_matchall_entry_find(&sparx5->mall_entries,
176					      tmo->cookie);
177	if (!entry)
178		return -ENOENT;
179
180	if (entry->type == FLOW_ACTION_MIRRED) {
181		sparx5_mirror_stats(entry, &tmo->stats);
182	} else {
183		NL_SET_ERR_MSG_MOD(tmo->common.extack, "Unsupported action");
184		return -EOPNOTSUPP;
185	}
186
187	return 0;
188}
189
190int sparx5_tc_matchall(struct net_device *ndev,
191		       struct tc_cls_matchall_offload *tmo,
192		       bool ingress)
193{
194	switch (tmo->command) {
195	case TC_CLSMATCHALL_REPLACE:
196		return sparx5_tc_matchall_replace(ndev, tmo, ingress);
197	case TC_CLSMATCHALL_DESTROY:
198		return sparx5_tc_matchall_destroy(ndev, tmo, ingress);
199	case TC_CLSMATCHALL_STATS:
200		return sparx5_tc_matchall_stats(ndev, tmo, ingress);
201	default:
202		return -EOPNOTSUPP;
203	}
204}