]> git.proxmox.com Git - mirror_ubuntu-artful-kernel.git/blobdiff - drivers/net/ethernet/mellanox/mlxsw/spectrum.c
Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/net
[mirror_ubuntu-artful-kernel.git] / drivers / net / ethernet / mellanox / mlxsw / spectrum.c
index 003093abb1707f0a6cdefe465e073c005d2ee3f9..3dbd82e636f8d77e8af8bb90e051f1efcb456ea9 100644 (file)
@@ -948,15 +948,13 @@ out:
 /* Return the stats from a cache that is updated periodically,
  * as this function might get called in an atomic context.
  */
-static struct rtnl_link_stats64 *
+static void
 mlxsw_sp_port_get_stats64(struct net_device *dev,
                          struct rtnl_link_stats64 *stats)
 {
        struct mlxsw_sp_port *mlxsw_sp_port = netdev_priv(dev);
 
        memcpy(stats, mlxsw_sp_port->hw_stats.cache, sizeof(*stats));
-
-       return stats;
 }
 
 int mlxsw_sp_port_vlan_set(struct mlxsw_sp_port *mlxsw_sp_port, u16 vid_begin,
@@ -1164,8 +1162,8 @@ static int mlxsw_sp_port_get_phys_port_name(struct net_device *dev, char *name,
 }
 
 static struct mlxsw_sp_port_mall_tc_entry *
-mlxsw_sp_port_mirror_entry_find(struct mlxsw_sp_port *port,
-                               unsigned long cookie) {
+mlxsw_sp_port_mall_tc_entry_find(struct mlxsw_sp_port *port,
+                                unsigned long cookie) {
        struct mlxsw_sp_port_mall_tc_entry *mall_tc_entry;
 
        list_for_each_entry(mall_tc_entry, &port->mall_tc_list, list)
@@ -1177,17 +1175,15 @@ mlxsw_sp_port_mirror_entry_find(struct mlxsw_sp_port *port,
 
 static int
 mlxsw_sp_port_add_cls_matchall_mirror(struct mlxsw_sp_port *mlxsw_sp_port,
-                                     struct tc_cls_matchall_offload *cls,
+                                     struct mlxsw_sp_port_mall_mirror_tc_entry *mirror,
                                      const struct tc_action *a,
                                      bool ingress)
 {
-       struct mlxsw_sp_port_mall_tc_entry *mall_tc_entry;
        struct net *net = dev_net(mlxsw_sp_port->dev);
        enum mlxsw_sp_span_type span_type;
        struct mlxsw_sp_port *to_port;
        struct net_device *to_dev;
        int ifindex;
-       int err;
 
        ifindex = tcf_mirred_ifindex(a);
        to_dev = __dev_get_by_index(net, ifindex);
@@ -1198,30 +1194,28 @@ mlxsw_sp_port_add_cls_matchall_mirror(struct mlxsw_sp_port *mlxsw_sp_port,
 
        if (!mlxsw_sp_port_dev_check(to_dev)) {
                netdev_err(mlxsw_sp_port->dev, "Cannot mirror to a non-spectrum port");
-               return -ENOTSUPP;
+               return -EOPNOTSUPP;
        }
        to_port = netdev_priv(to_dev);
 
-       mall_tc_entry = kzalloc(sizeof(*mall_tc_entry), GFP_KERNEL);
-       if (!mall_tc_entry)
-               return -ENOMEM;
-
-       mall_tc_entry->cookie = cls->cookie;
-       mall_tc_entry->type = MLXSW_SP_PORT_MALL_MIRROR;
-       mall_tc_entry->mirror.to_local_port = to_port->local_port;
-       mall_tc_entry->mirror.ingress = ingress;
-       list_add_tail(&mall_tc_entry->list, &mlxsw_sp_port->mall_tc_list);
-
+       mirror->to_local_port = to_port->local_port;
+       mirror->ingress = ingress;
        span_type = ingress ? MLXSW_SP_SPAN_INGRESS : MLXSW_SP_SPAN_EGRESS;
-       err = mlxsw_sp_span_mirror_add(mlxsw_sp_port, to_port, span_type);
-       if (err)
-               goto err_mirror_add;
-       return 0;
+       return mlxsw_sp_span_mirror_add(mlxsw_sp_port, to_port, span_type);
+}
 
-err_mirror_add:
-       list_del(&mall_tc_entry->list);
-       kfree(mall_tc_entry);
-       return err;
+static void
+mlxsw_sp_port_del_cls_matchall_mirror(struct mlxsw_sp_port *mlxsw_sp_port,
+                                     struct mlxsw_sp_port_mall_mirror_tc_entry *mirror)
+{
+       struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
+       enum mlxsw_sp_span_type span_type;
+       struct mlxsw_sp_port *to_port;
+
+       to_port = mlxsw_sp->ports[mirror->to_local_port];
+       span_type = mirror->ingress ?
+                       MLXSW_SP_SPAN_INGRESS : MLXSW_SP_SPAN_EGRESS;
+       mlxsw_sp_span_mirror_remove(mlxsw_sp_port, to_port, span_type);
 }
 
 static int mlxsw_sp_port_add_cls_matchall(struct mlxsw_sp_port *mlxsw_sp_port,
@@ -1229,59 +1223,68 @@ static int mlxsw_sp_port_add_cls_matchall(struct mlxsw_sp_port *mlxsw_sp_port,
                                          struct tc_cls_matchall_offload *cls,
                                          bool ingress)
 {
+       struct mlxsw_sp_port_mall_tc_entry *mall_tc_entry;
        const struct tc_action *a;
        LIST_HEAD(actions);
        int err;
 
        if (!tc_single_action(cls->exts)) {
                netdev_err(mlxsw_sp_port->dev, "only singular actions are supported\n");
-               return -ENOTSUPP;
+               return -EOPNOTSUPP;
        }
 
+       mall_tc_entry = kzalloc(sizeof(*mall_tc_entry), GFP_KERNEL);
+       if (!mall_tc_entry)
+               return -ENOMEM;
+       mall_tc_entry->cookie = cls->cookie;
+
        tcf_exts_to_list(cls->exts, &actions);
-       list_for_each_entry(a, &actions, list) {
-               if (!is_tcf_mirred_egress_mirror(a) ||
-                   protocol != htons(ETH_P_ALL)) {
-                       return -ENOTSUPP;
-               }
+       a = list_first_entry(&actions, struct tc_action, list);
 
-               err = mlxsw_sp_port_add_cls_matchall_mirror(mlxsw_sp_port, cls,
-                                                           a, ingress);
-               if (err)
-                       return err;
+       if (is_tcf_mirred_egress_mirror(a) && protocol == htons(ETH_P_ALL)) {
+               struct mlxsw_sp_port_mall_mirror_tc_entry *mirror;
+
+               mall_tc_entry->type = MLXSW_SP_PORT_MALL_MIRROR;
+               mirror = &mall_tc_entry->mirror;
+               err = mlxsw_sp_port_add_cls_matchall_mirror(mlxsw_sp_port,
+                                                           mirror, a, ingress);
+       } else {
+               err = -EOPNOTSUPP;
        }
 
+       if (err)
+               goto err_add_action;
+
+       list_add_tail(&mall_tc_entry->list, &mlxsw_sp_port->mall_tc_list);
        return 0;
+
+err_add_action:
+       kfree(mall_tc_entry);
+       return err;
 }
 
 static void mlxsw_sp_port_del_cls_matchall(struct mlxsw_sp_port *mlxsw_sp_port,
                                           struct tc_cls_matchall_offload *cls)
 {
-       struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
        struct mlxsw_sp_port_mall_tc_entry *mall_tc_entry;
-       enum mlxsw_sp_span_type span_type;
-       struct mlxsw_sp_port *to_port;
 
-       mall_tc_entry = mlxsw_sp_port_mirror_entry_find(mlxsw_sp_port,
-                                                       cls->cookie);
+       mall_tc_entry = mlxsw_sp_port_mall_tc_entry_find(mlxsw_sp_port,
+                                                        cls->cookie);
        if (!mall_tc_entry) {
                netdev_dbg(mlxsw_sp_port->dev, "tc entry not found on port\n");
                return;
        }
+       list_del(&mall_tc_entry->list);
 
        switch (mall_tc_entry->type) {
        case MLXSW_SP_PORT_MALL_MIRROR:
-               to_port = mlxsw_sp->ports[mall_tc_entry->mirror.to_local_port];
-               span_type = mall_tc_entry->mirror.ingress ?
-                               MLXSW_SP_SPAN_INGRESS : MLXSW_SP_SPAN_EGRESS;
-
-               mlxsw_sp_span_mirror_remove(mlxsw_sp_port, to_port, span_type);
+               mlxsw_sp_port_del_cls_matchall_mirror(mlxsw_sp_port,
+                                                     &mall_tc_entry->mirror);
                break;
        default:
                WARN_ON(1);
        }
 
-       list_del(&mall_tc_entry->list);
        kfree(mall_tc_entry);
 }
 
@@ -1307,7 +1310,7 @@ static int mlxsw_sp_setup_tc(struct net_device *dev, u32 handle,
                }
        }
 
-       return -ENOTSUPP;
+       return -EOPNOTSUPP;
 }
 
 static const struct net_device_ops mlxsw_sp_port_netdev_ops = {
@@ -1650,7 +1653,7 @@ mlxsw_sp_get_hw_stats_by_group(struct mlxsw_sp_port_hw_stats **p_hw_stats,
                break;
        default:
                WARN_ON(1);
-               return -ENOTSUPP;
+               return -EOPNOTSUPP;
        }
        return 0;
 }
@@ -2429,8 +2432,8 @@ static void __mlxsw_sp_port_remove(struct mlxsw_sp *mlxsw_sp, u8 local_port)
        mlxsw_sp_port_dcb_fini(mlxsw_sp_port);
        mlxsw_sp_port_swid_set(mlxsw_sp_port, MLXSW_PORT_SWID_DISABLED_PORT);
        mlxsw_sp_port_module_unmap(mlxsw_sp, mlxsw_sp_port->local_port);
-       free_percpu(mlxsw_sp_port->pcpu_stats);
        kfree(mlxsw_sp_port->hw_stats.cache);
+       free_percpu(mlxsw_sp_port->pcpu_stats);
        kfree(mlxsw_sp_port->untagged_vlans);
        kfree(mlxsw_sp_port->active_vlans);
        WARN_ON_ONCE(!list_empty(&mlxsw_sp_port->vports_list));