OSDN Git Service

net: dsa: add MRP support
authorHoratiu Vultur <horatiu.vultur@microchip.com>
Tue, 16 Feb 2021 21:42:04 +0000 (22:42 +0100)
committerDavid S. Miller <davem@davemloft.net>
Tue, 16 Feb 2021 22:47:46 +0000 (14:47 -0800)
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>
include/net/dsa.h
net/dsa/dsa_priv.h
net/dsa/port.c
net/dsa/slave.c
net/dsa/switch.c

index 68f8159..83a933e 100644 (file)
@@ -792,6 +792,18 @@ struct dsa_switch_ops {
                                 struct net_device *hsr);
        int     (*port_hsr_leave)(struct dsa_switch *ds, int port,
                                  struct net_device *hsr);
+
+       /*
+        * MRP integration
+        */
+       int     (*port_mrp_add)(struct dsa_switch *ds, int port,
+                               const struct switchdev_obj_mrp *mrp);
+       int     (*port_mrp_del)(struct dsa_switch *ds, int port,
+                               const struct switchdev_obj_mrp *mrp);
+       int     (*port_mrp_add_ring_role)(struct dsa_switch *ds, int port,
+                                         const struct switchdev_obj_ring_role_mrp *mrp);
+       int     (*port_mrp_del_ring_role)(struct dsa_switch *ds, int port,
+                                         const struct switchdev_obj_ring_role_mrp *mrp);
 };
 
 #define DSA_DEVLINK_PARAM_DRIVER(_id, _name, _type, _cmodes)           \
index e9d1e76..2eeaa42 100644 (file)
@@ -31,6 +31,10 @@ enum {
        DSA_NOTIFIER_VLAN_DEL,
        DSA_NOTIFIER_MTU,
        DSA_NOTIFIER_TAG_PROTO,
+       DSA_NOTIFIER_MRP_ADD,
+       DSA_NOTIFIER_MRP_DEL,
+       DSA_NOTIFIER_MRP_ADD_RING_ROLE,
+       DSA_NOTIFIER_MRP_DEL_RING_ROLE,
 };
 
 /* DSA_NOTIFIER_AGEING_TIME */
@@ -91,6 +95,20 @@ struct dsa_notifier_tag_proto_info {
        const struct dsa_device_ops *tag_ops;
 };
 
+/* DSA_NOTIFIER_MRP_* */
+struct dsa_notifier_mrp_info {
+       const struct switchdev_obj_mrp *mrp;
+       int sw_index;
+       int port;
+};
+
+/* DSA_NOTIFIER_MRP_* */
+struct dsa_notifier_mrp_ring_role_info {
+       const struct switchdev_obj_ring_role_mrp *mrp;
+       int sw_index;
+       int port;
+};
+
 struct dsa_switchdev_event_work {
        struct dsa_switch *ds;
        int port;
@@ -198,6 +216,14 @@ int dsa_port_vlan_add(struct dsa_port *dp,
                      struct netlink_ext_ack *extack);
 int dsa_port_vlan_del(struct dsa_port *dp,
                      const struct switchdev_obj_port_vlan *vlan);
+int dsa_port_mrp_add(const struct dsa_port *dp,
+                    const struct switchdev_obj_mrp *mrp);
+int dsa_port_mrp_del(const struct dsa_port *dp,
+                    const struct switchdev_obj_mrp *mrp);
+int dsa_port_mrp_add_ring_role(const struct dsa_port *dp,
+                              const struct switchdev_obj_ring_role_mrp *mrp);
+int dsa_port_mrp_del_ring_role(const struct dsa_port *dp,
+                              const struct switchdev_obj_ring_role_mrp *mrp);
 int dsa_port_link_register_of(struct dsa_port *dp);
 void dsa_port_link_unregister_of(struct dsa_port *dp);
 int dsa_port_hsr_join(struct dsa_port *dp, struct net_device *hsr);
index 14a1d0d..c9c6d7a 100644 (file)
@@ -564,6 +564,54 @@ int dsa_port_vlan_del(struct dsa_port *dp,
        return dsa_port_notify(dp, DSA_NOTIFIER_VLAN_DEL, &info);
 }
 
+int dsa_port_mrp_add(const struct dsa_port *dp,
+                    const struct switchdev_obj_mrp *mrp)
+{
+       struct dsa_notifier_mrp_info info = {
+               .sw_index = dp->ds->index,
+               .port = dp->index,
+               .mrp = mrp,
+       };
+
+       return dsa_port_notify(dp, DSA_NOTIFIER_MRP_ADD, &info);
+}
+
+int dsa_port_mrp_del(const struct dsa_port *dp,
+                    const struct switchdev_obj_mrp *mrp)
+{
+       struct dsa_notifier_mrp_info info = {
+               .sw_index = dp->ds->index,
+               .port = dp->index,
+               .mrp = mrp,
+       };
+
+       return dsa_port_notify(dp, DSA_NOTIFIER_MRP_DEL, &info);
+}
+
+int dsa_port_mrp_add_ring_role(const struct dsa_port *dp,
+                              const struct switchdev_obj_ring_role_mrp *mrp)
+{
+       struct dsa_notifier_mrp_ring_role_info info = {
+               .sw_index = dp->ds->index,
+               .port = dp->index,
+               .mrp = mrp,
+       };
+
+       return dsa_port_notify(dp, DSA_NOTIFIER_MRP_ADD_RING_ROLE, &info);
+}
+
+int dsa_port_mrp_del_ring_role(const struct dsa_port *dp,
+                              const struct switchdev_obj_ring_role_mrp *mrp)
+{
+       struct dsa_notifier_mrp_ring_role_info info = {
+               .sw_index = dp->ds->index,
+               .port = dp->index,
+               .mrp = mrp,
+       };
+
+       return dsa_port_notify(dp, DSA_NOTIFIER_MRP_DEL_RING_ROLE, &info);
+}
+
 void dsa_port_set_tag_protocol(struct dsa_port *cpu_dp,
                               const struct dsa_device_ops *tag_ops)
 {
index 5ecb43a..491e376 100644 (file)
@@ -404,6 +404,17 @@ static int dsa_slave_port_obj_add(struct net_device *dev,
        case SWITCHDEV_OBJ_ID_PORT_VLAN:
                err = dsa_slave_vlan_add(dev, obj, extack);
                break;
+       case SWITCHDEV_OBJ_ID_MRP:
+               if (!dsa_port_offloads_netdev(dp, obj->orig_dev))
+                       return -EOPNOTSUPP;
+               err = dsa_port_mrp_add(dp, SWITCHDEV_OBJ_MRP(obj));
+               break;
+       case SWITCHDEV_OBJ_ID_RING_ROLE_MRP:
+               if (!dsa_port_offloads_netdev(dp, obj->orig_dev))
+                       return -EOPNOTSUPP;
+               err = dsa_port_mrp_add_ring_role(dp,
+                                                SWITCHDEV_OBJ_RING_ROLE_MRP(obj));
+               break;
        default:
                err = -EOPNOTSUPP;
                break;
@@ -461,6 +472,17 @@ static int dsa_slave_port_obj_del(struct net_device *dev,
        case SWITCHDEV_OBJ_ID_PORT_VLAN:
                err = dsa_slave_vlan_del(dev, obj);
                break;
+       case SWITCHDEV_OBJ_ID_MRP:
+               if (!dsa_port_offloads_netdev(dp, obj->orig_dev))
+                       return -EOPNOTSUPP;
+               err = dsa_port_mrp_del(dp, SWITCHDEV_OBJ_MRP(obj));
+               break;
+       case SWITCHDEV_OBJ_ID_RING_ROLE_MRP:
+               if (!dsa_port_offloads_netdev(dp, obj->orig_dev))
+                       return -EOPNOTSUPP;
+               err = dsa_port_mrp_del_ring_role(dp,
+                                                SWITCHDEV_OBJ_RING_ROLE_MRP(obj));
+               break;
        default:
                err = -EOPNOTSUPP;
                break;
index db2a9b2..4b5da89 100644 (file)
@@ -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;