summaryrefslogtreecommitdiff
path: root/net/dsa/switch.c
diff options
context:
space:
mode:
authorHoratiu Vultur <horatiu.vultur@microchip.com>2021-02-16 22:42:04 +0100
committerDavid S. Miller <davem@davemloft.net>2021-02-16 14:47:46 -0800
commitc595c4330da06fff716337239a8d5e528341a502 (patch)
tree9ac40eb2f5027cd6b6ac226660be82f66caee548 /net/dsa/switch.c
parentd8ea7ff3995ead5193313c72c0d97c9c16c83be9 (diff)
net: dsa: add MRP support
Add support for offloading MRP in HW. Currently implement the switchdev calls 'SWITCHDEV_OBJ_ID_MRP', 'SWITCHDEV_OBJ_ID_RING_ROLE_MRP', to allow to create MRP instances and to set the role of these instances. Add DSA_NOTIFIER_MRP_ADD/DEL and DSA_NOTIFIER_MRP_ADD/DEL_RING_ROLE which calls to .port_mrp_add/del and .port_mrp_add/del_ring_role in the DSA driver for the switch. Signed-off-by: Horatiu Vultur <horatiu.vultur@microchip.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/dsa/switch.c')
-rw-r--r--net/dsa/switch.c105
1 files changed, 105 insertions, 0 deletions
diff --git a/net/dsa/switch.c b/net/dsa/switch.c
index db2a9b221988..4b5da89dc27a 100644
--- a/net/dsa/switch.c
+++ b/net/dsa/switch.c
@@ -372,6 +372,99 @@ static int dsa_switch_change_tag_proto(struct dsa_switch *ds,
return 0;
}
+static bool dsa_switch_mrp_match(struct dsa_switch *ds, int port,
+ struct dsa_notifier_mrp_info *info)
+{
+ if (ds->index == info->sw_index && port == info->port)
+ return true;
+
+ if (dsa_is_dsa_port(ds, port))
+ return true;
+
+ return false;
+}
+
+static int dsa_switch_mrp_add(struct dsa_switch *ds,
+ struct dsa_notifier_mrp_info *info)
+{
+ int err = 0;
+ int port;
+
+ if (!ds->ops->port_mrp_add)
+ return -EOPNOTSUPP;
+
+ for (port = 0; port < ds->num_ports; port++) {
+ if (dsa_switch_mrp_match(ds, port, info)) {
+ err = ds->ops->port_mrp_add(ds, port, info->mrp);
+ if (err)
+ break;
+ }
+ }
+
+ return err;
+}
+
+static int dsa_switch_mrp_del(struct dsa_switch *ds,
+ struct dsa_notifier_mrp_info *info)
+{
+ if (!ds->ops->port_mrp_del)
+ return -EOPNOTSUPP;
+
+ if (ds->index == info->sw_index)
+ return ds->ops->port_mrp_del(ds, info->port, info->mrp);
+
+ return 0;
+}
+
+static bool
+dsa_switch_mrp_ring_role_match(struct dsa_switch *ds, int port,
+ struct dsa_notifier_mrp_ring_role_info *info)
+{
+ if (ds->index == info->sw_index && port == info->port)
+ return true;
+
+ if (dsa_is_dsa_port(ds, port))
+ return true;
+
+ return false;
+}
+
+static int
+dsa_switch_mrp_add_ring_role(struct dsa_switch *ds,
+ struct dsa_notifier_mrp_ring_role_info *info)
+{
+ int err = 0;
+ int port;
+
+ if (!ds->ops->port_mrp_add)
+ return -EOPNOTSUPP;
+
+ for (port = 0; port < ds->num_ports; port++) {
+ if (dsa_switch_mrp_ring_role_match(ds, port, info)) {
+ err = ds->ops->port_mrp_add_ring_role(ds, port,
+ info->mrp);
+ if (err)
+ break;
+ }
+ }
+
+ return err;
+}
+
+static int
+dsa_switch_mrp_del_ring_role(struct dsa_switch *ds,
+ struct dsa_notifier_mrp_ring_role_info *info)
+{
+ if (!ds->ops->port_mrp_del)
+ return -EOPNOTSUPP;
+
+ if (ds->index == info->sw_index)
+ return ds->ops->port_mrp_del_ring_role(ds, info->port,
+ info->mrp);
+
+ return 0;
+}
+
static int dsa_switch_event(struct notifier_block *nb,
unsigned long event, void *info)
{
@@ -427,6 +520,18 @@ static int dsa_switch_event(struct notifier_block *nb,
case DSA_NOTIFIER_TAG_PROTO:
err = dsa_switch_change_tag_proto(ds, info);
break;
+ case DSA_NOTIFIER_MRP_ADD:
+ err = dsa_switch_mrp_add(ds, info);
+ break;
+ case DSA_NOTIFIER_MRP_DEL:
+ err = dsa_switch_mrp_del(ds, info);
+ break;
+ case DSA_NOTIFIER_MRP_ADD_RING_ROLE:
+ err = dsa_switch_mrp_add_ring_role(ds, info);
+ break;
+ case DSA_NOTIFIER_MRP_DEL_RING_ROLE:
+ err = dsa_switch_mrp_del_ring_role(ds, info);
+ break;
default:
err = -EOPNOTSUPP;
break;