1 // SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0
2 /* Copyright (c) 2020 Marvell International Ltd. All rights reserved */
4 #include <linux/kernel.h>
5 #include <linux/list.h>
8 #include "prestera_hw.h"
9 #include "prestera_acl.h"
10 #include "prestera_flow.h"
11 #include "prestera_span.h"
13 struct prestera_span_entry {
14 struct list_head list;
15 struct prestera_port *port;
20 struct prestera_span {
21 struct prestera_switch *sw;
22 struct list_head entries;
25 static struct prestera_span_entry *
26 prestera_span_entry_create(struct prestera_port *port, u8 span_id)
28 struct prestera_span_entry *entry;
30 entry = kzalloc(sizeof(*entry), GFP_KERNEL);
32 return ERR_PTR(-ENOMEM);
34 refcount_set(&entry->ref_count, 1);
37 list_add_tail(&entry->list, &port->sw->span->entries);
42 static void prestera_span_entry_del(struct prestera_span_entry *entry)
44 list_del(&entry->list);
48 static struct prestera_span_entry *
49 prestera_span_entry_find_by_id(struct prestera_span *span, u8 span_id)
51 struct prestera_span_entry *entry;
53 list_for_each_entry(entry, &span->entries, list) {
54 if (entry->id == span_id)
61 static struct prestera_span_entry *
62 prestera_span_entry_find_by_port(struct prestera_span *span,
63 struct prestera_port *port)
65 struct prestera_span_entry *entry;
67 list_for_each_entry(entry, &span->entries, list) {
68 if (entry->port == port)
75 static int prestera_span_get(struct prestera_port *port, u8 *span_id)
78 struct prestera_switch *sw = port->sw;
79 struct prestera_span_entry *entry;
82 entry = prestera_span_entry_find_by_port(sw->span, port);
84 refcount_inc(&entry->ref_count);
89 err = prestera_hw_span_get(port, &new_span_id);
93 entry = prestera_span_entry_create(port, new_span_id);
95 prestera_hw_span_release(sw, new_span_id);
96 return PTR_ERR(entry);
99 *span_id = new_span_id;
103 static int prestera_span_put(struct prestera_switch *sw, u8 span_id)
105 struct prestera_span_entry *entry;
108 entry = prestera_span_entry_find_by_id(sw->span, span_id);
112 if (!refcount_dec_and_test(&entry->ref_count))
115 err = prestera_hw_span_release(sw, span_id);
119 prestera_span_entry_del(entry);
123 int prestera_span_rule_add(struct prestera_flow_block_binding *binding,
124 struct prestera_port *to_port,
127 struct prestera_switch *sw = binding->port->sw;
131 if (binding->span_id != PRESTERA_SPAN_INVALID_ID)
132 /* port already in mirroring */
135 err = prestera_span_get(to_port, &span_id);
139 err = prestera_hw_span_bind(binding->port, span_id, ingress);
141 prestera_span_put(sw, span_id);
145 binding->span_id = span_id;
149 int prestera_span_rule_del(struct prestera_flow_block_binding *binding,
154 err = prestera_hw_span_unbind(binding->port, ingress);
158 err = prestera_span_put(binding->port->sw, binding->span_id);
162 binding->span_id = PRESTERA_SPAN_INVALID_ID;
166 int prestera_span_init(struct prestera_switch *sw)
168 struct prestera_span *span;
170 span = kzalloc(sizeof(*span), GFP_KERNEL);
174 INIT_LIST_HEAD(&span->entries);
182 void prestera_span_fini(struct prestera_switch *sw)
184 struct prestera_span *span = sw->span;
186 WARN_ON(!list_empty(&span->entries));