brintos

brintos / linux-shallow public Read only

0
0
Text · 3.8 KiB · 1005182 Raw
192 lines · c
1// SPDX-License-Identifier: BSD-3-Clause OR GPL-2.02/* Copyright (c) 2020 Marvell International Ltd. All rights reserved */3 4#include <linux/kernel.h>5#include <linux/list.h>6 7#include "prestera.h"8#include "prestera_hw.h"9#include "prestera_acl.h"10#include "prestera_flow.h"11#include "prestera_span.h"12 13struct prestera_span_entry {14	struct list_head list;15	struct prestera_port *port;16	refcount_t ref_count;17	u8 id;18};19 20struct prestera_span {21	struct prestera_switch *sw;22	struct list_head entries;23};24 25static struct prestera_span_entry *26prestera_span_entry_create(struct prestera_port *port, u8 span_id)27{28	struct prestera_span_entry *entry;29 30	entry = kzalloc(sizeof(*entry), GFP_KERNEL);31	if (!entry)32		return ERR_PTR(-ENOMEM);33 34	refcount_set(&entry->ref_count, 1);35	entry->port = port;36	entry->id = span_id;37	list_add_tail(&entry->list, &port->sw->span->entries);38 39	return entry;40}41 42static void prestera_span_entry_del(struct prestera_span_entry *entry)43{44	list_del(&entry->list);45	kfree(entry);46}47 48static struct prestera_span_entry *49prestera_span_entry_find_by_id(struct prestera_span *span, u8 span_id)50{51	struct prestera_span_entry *entry;52 53	list_for_each_entry(entry, &span->entries, list) {54		if (entry->id == span_id)55			return entry;56	}57 58	return NULL;59}60 61static struct prestera_span_entry *62prestera_span_entry_find_by_port(struct prestera_span *span,63				 struct prestera_port *port)64{65	struct prestera_span_entry *entry;66 67	list_for_each_entry(entry, &span->entries, list) {68		if (entry->port == port)69			return entry;70	}71 72	return NULL;73}74 75static int prestera_span_get(struct prestera_port *port, u8 *span_id)76{77	u8 new_span_id;78	struct prestera_switch *sw = port->sw;79	struct prestera_span_entry *entry;80	int err;81 82	entry = prestera_span_entry_find_by_port(sw->span, port);83	if (entry) {84		refcount_inc(&entry->ref_count);85		*span_id = entry->id;86		return 0;87	}88 89	err = prestera_hw_span_get(port, &new_span_id);90	if (err)91		return err;92 93	entry = prestera_span_entry_create(port, new_span_id);94	if (IS_ERR(entry)) {95		prestera_hw_span_release(sw, new_span_id);96		return PTR_ERR(entry);97	}98 99	*span_id = new_span_id;100	return 0;101}102 103static int prestera_span_put(struct prestera_switch *sw, u8 span_id)104{105	struct prestera_span_entry *entry;106	int err;107 108	entry = prestera_span_entry_find_by_id(sw->span, span_id);109	if (!entry)110		return -ENOENT;111 112	if (!refcount_dec_and_test(&entry->ref_count))113		return 0;114 115	err = prestera_hw_span_release(sw, span_id);116	if (err)117		return err;118 119	prestera_span_entry_del(entry);120	return 0;121}122 123int prestera_span_rule_add(struct prestera_flow_block_binding *binding,124			   struct prestera_port *to_port,125			   bool ingress)126{127	struct prestera_switch *sw = binding->port->sw;128	u8 span_id;129	int err;130 131	if (binding->span_id != PRESTERA_SPAN_INVALID_ID)132		/* port already in mirroring */133		return -EEXIST;134 135	err = prestera_span_get(to_port, &span_id);136	if (err)137		return err;138 139	err = prestera_hw_span_bind(binding->port, span_id, ingress);140	if (err) {141		prestera_span_put(sw, span_id);142		return err;143	}144 145	binding->span_id = span_id;146	return 0;147}148 149int prestera_span_rule_del(struct prestera_flow_block_binding *binding,150			   bool ingress)151{152	int err;153 154	if (binding->span_id == PRESTERA_SPAN_INVALID_ID)155		return -ENOENT;156 157	err = prestera_hw_span_unbind(binding->port, ingress);158	if (err)159		return err;160 161	err = prestera_span_put(binding->port->sw, binding->span_id);162	if (err)163		return err;164 165	binding->span_id = PRESTERA_SPAN_INVALID_ID;166	return 0;167}168 169int prestera_span_init(struct prestera_switch *sw)170{171	struct prestera_span *span;172 173	span = kzalloc(sizeof(*span), GFP_KERNEL);174	if (!span)175		return -ENOMEM;176 177	INIT_LIST_HEAD(&span->entries);178 179	sw->span = span;180	span->sw = sw;181 182	return 0;183}184 185void prestera_span_fini(struct prestera_switch *sw)186{187	struct prestera_span *span = sw->span;188 189	WARN_ON(!list_empty(&span->entries));190	kfree(span);191}192