mlxsw: Track per-module port status
authorIdo Schimmel <idosch@nvidia.com>
Wed, 15 Sep 2021 10:13:11 +0000 (13:13 +0300)
committerDavid S. Miller <davem@davemloft.net>
Wed, 15 Sep 2021 15:17:16 +0000 (16:17 +0100)
In the common port module core, track the number of logical ports that
are mapped to the port module and the number of logical ports using it
that are administratively up.

This will be used by later patches to potentially veto and control
certain operations on the module, such as reset and setting its power
mode.

Signed-off-by: Ido Schimmel <idosch@nvidia.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
drivers/net/ethernet/mellanox/mlxsw/core_env.c
drivers/net/ethernet/mellanox/mlxsw/core_env.h
drivers/net/ethernet/mellanox/mlxsw/minimal.c
drivers/net/ethernet/mellanox/mlxsw/spectrum.c

index 543f401..c7b7254 100644 (file)
@@ -15,6 +15,8 @@
 struct mlxsw_env_module_info {
        u64 module_overheat_counter;
        bool is_overheat;
+       int num_ports_mapped;
+       int num_ports_up;
 };
 
 struct mlxsw_env {
@@ -708,6 +710,60 @@ mlxsw_env_module_overheat_counter_get(struct mlxsw_core *mlxsw_core, u8 module,
 }
 EXPORT_SYMBOL(mlxsw_env_module_overheat_counter_get);
 
+void mlxsw_env_module_port_map(struct mlxsw_core *mlxsw_core, u8 module)
+{
+       struct mlxsw_env *mlxsw_env = mlxsw_core_env(mlxsw_core);
+
+       if (WARN_ON_ONCE(module >= mlxsw_env->module_count))
+               return;
+
+       mutex_lock(&mlxsw_env->module_info_lock);
+       mlxsw_env->module_info[module].num_ports_mapped++;
+       mutex_unlock(&mlxsw_env->module_info_lock);
+}
+EXPORT_SYMBOL(mlxsw_env_module_port_map);
+
+void mlxsw_env_module_port_unmap(struct mlxsw_core *mlxsw_core, u8 module)
+{
+       struct mlxsw_env *mlxsw_env = mlxsw_core_env(mlxsw_core);
+
+       if (WARN_ON_ONCE(module >= mlxsw_env->module_count))
+               return;
+
+       mutex_lock(&mlxsw_env->module_info_lock);
+       mlxsw_env->module_info[module].num_ports_mapped--;
+       mutex_unlock(&mlxsw_env->module_info_lock);
+}
+EXPORT_SYMBOL(mlxsw_env_module_port_unmap);
+
+int mlxsw_env_module_port_up(struct mlxsw_core *mlxsw_core, u8 module)
+{
+       struct mlxsw_env *mlxsw_env = mlxsw_core_env(mlxsw_core);
+
+       if (WARN_ON_ONCE(module >= mlxsw_env->module_count))
+               return -EINVAL;
+
+       mutex_lock(&mlxsw_env->module_info_lock);
+       mlxsw_env->module_info[module].num_ports_up++;
+       mutex_unlock(&mlxsw_env->module_info_lock);
+
+       return 0;
+}
+EXPORT_SYMBOL(mlxsw_env_module_port_up);
+
+void mlxsw_env_module_port_down(struct mlxsw_core *mlxsw_core, u8 module)
+{
+       struct mlxsw_env *mlxsw_env = mlxsw_core_env(mlxsw_core);
+
+       if (WARN_ON_ONCE(module >= mlxsw_env->module_count))
+               return;
+
+       mutex_lock(&mlxsw_env->module_info_lock);
+       mlxsw_env->module_info[module].num_ports_up--;
+       mutex_unlock(&mlxsw_env->module_info_lock);
+}
+EXPORT_SYMBOL(mlxsw_env_module_port_down);
+
 int mlxsw_env_init(struct mlxsw_core *mlxsw_core, struct mlxsw_env **p_env)
 {
        char mgpir_pl[MLXSW_REG_MGPIR_LEN];
index 0bf5bd0..ba9269f 100644 (file)
@@ -27,6 +27,15 @@ mlxsw_env_get_module_eeprom_by_page(struct mlxsw_core *mlxsw_core, u8 module,
 int
 mlxsw_env_module_overheat_counter_get(struct mlxsw_core *mlxsw_core, u8 module,
                                      u64 *p_counter);
+
+void mlxsw_env_module_port_map(struct mlxsw_core *mlxsw_core, u8 module);
+
+void mlxsw_env_module_port_unmap(struct mlxsw_core *mlxsw_core, u8 module);
+
+int mlxsw_env_module_port_up(struct mlxsw_core *mlxsw_core, u8 module);
+
+void mlxsw_env_module_port_down(struct mlxsw_core *mlxsw_core, u8 module);
+
 int mlxsw_env_init(struct mlxsw_core *core, struct mlxsw_env **p_env);
 void mlxsw_env_fini(struct mlxsw_env *env);
 
index d9d56c4..a3eca0b 100644 (file)
@@ -54,8 +54,20 @@ static int mlxsw_m_base_mac_get(struct mlxsw_m *mlxsw_m)
        return 0;
 }
 
-static int mlxsw_m_port_dummy_open_stop(struct net_device *dev)
+static int mlxsw_m_port_open(struct net_device *dev)
 {
+       struct mlxsw_m_port *mlxsw_m_port = netdev_priv(dev);
+       struct mlxsw_m *mlxsw_m = mlxsw_m_port->mlxsw_m;
+
+       return mlxsw_env_module_port_up(mlxsw_m->core, mlxsw_m_port->module);
+}
+
+static int mlxsw_m_port_stop(struct net_device *dev)
+{
+       struct mlxsw_m_port *mlxsw_m_port = netdev_priv(dev);
+       struct mlxsw_m *mlxsw_m = mlxsw_m_port->mlxsw_m;
+
+       mlxsw_env_module_port_down(mlxsw_m->core, mlxsw_m_port->module);
        return 0;
 }
 
@@ -70,8 +82,8 @@ mlxsw_m_port_get_devlink_port(struct net_device *dev)
 }
 
 static const struct net_device_ops mlxsw_m_port_netdev_ops = {
-       .ndo_open               = mlxsw_m_port_dummy_open_stop,
-       .ndo_stop               = mlxsw_m_port_dummy_open_stop,
+       .ndo_open               = mlxsw_m_port_open,
+       .ndo_stop               = mlxsw_m_port_stop,
        .ndo_get_devlink_port   = mlxsw_m_port_get_devlink_port,
 };
 
@@ -266,6 +278,7 @@ static int mlxsw_m_port_module_map(struct mlxsw_m *mlxsw_m, u8 local_port,
 
        if (WARN_ON_ONCE(module >= max_ports))
                return -EINVAL;
+       mlxsw_env_module_port_map(mlxsw_m->core, module);
        mlxsw_m->module_to_port[module] = ++mlxsw_m->max_ports;
 
        return 0;
@@ -274,6 +287,7 @@ static int mlxsw_m_port_module_map(struct mlxsw_m *mlxsw_m, u8 local_port,
 static void mlxsw_m_port_module_unmap(struct mlxsw_m *mlxsw_m, u8 module)
 {
        mlxsw_m->module_to_port[module] = -1;
+       mlxsw_env_module_port_unmap(mlxsw_m->core, module);
 }
 
 static int mlxsw_m_ports_create(struct mlxsw_m *mlxsw_m)
index cea4118..0e81ae7 100644 (file)
@@ -539,7 +539,9 @@ mlxsw_sp_port_module_map(struct mlxsw_sp *mlxsw_sp, u8 local_port,
                         const struct mlxsw_sp_port_mapping *port_mapping)
 {
        char pmlp_pl[MLXSW_REG_PMLP_LEN];
-       int i;
+       int i, err;
+
+       mlxsw_env_module_port_map(mlxsw_sp->core, port_mapping->module);
 
        mlxsw_reg_pmlp_pack(pmlp_pl, local_port);
        mlxsw_reg_pmlp_width_set(pmlp_pl, port_mapping->width);
@@ -548,36 +550,58 @@ mlxsw_sp_port_module_map(struct mlxsw_sp *mlxsw_sp, u8 local_port,
                mlxsw_reg_pmlp_tx_lane_set(pmlp_pl, i, port_mapping->lane + i); /* Rx & Tx */
        }
 
-       return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(pmlp), pmlp_pl);
+       err = mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(pmlp), pmlp_pl);
+       if (err)
+               goto err_pmlp_write;
+       return 0;
+
+err_pmlp_write:
+       mlxsw_env_module_port_unmap(mlxsw_sp->core, port_mapping->module);
+       return err;
 }
 
-static void mlxsw_sp_port_module_unmap(struct mlxsw_sp *mlxsw_sp, u8 local_port)
+static void mlxsw_sp_port_module_unmap(struct mlxsw_sp *mlxsw_sp, u8 local_port,
+                                      u8 module)
 {
        char pmlp_pl[MLXSW_REG_PMLP_LEN];
 
        mlxsw_reg_pmlp_pack(pmlp_pl, local_port);
        mlxsw_reg_pmlp_width_set(pmlp_pl, 0);
        mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(pmlp), pmlp_pl);
+       mlxsw_env_module_port_unmap(mlxsw_sp->core, module);
 }
 
 static int mlxsw_sp_port_open(struct net_device *dev)
 {
        struct mlxsw_sp_port *mlxsw_sp_port = netdev_priv(dev);
+       struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
        int err;
 
-       err = mlxsw_sp_port_admin_status_set(mlxsw_sp_port, true);
+       err = mlxsw_env_module_port_up(mlxsw_sp->core,
+                                      mlxsw_sp_port->mapping.module);
        if (err)
                return err;
+       err = mlxsw_sp_port_admin_status_set(mlxsw_sp_port, true);
+       if (err)
+               goto err_port_admin_status_set;
        netif_start_queue(dev);
        return 0;
+
+err_port_admin_status_set:
+       mlxsw_env_module_port_down(mlxsw_sp->core,
+                                  mlxsw_sp_port->mapping.module);
+       return err;
 }
 
 static int mlxsw_sp_port_stop(struct net_device *dev)
 {
        struct mlxsw_sp_port *mlxsw_sp_port = netdev_priv(dev);
+       struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
 
        netif_stop_queue(dev);
        mlxsw_sp_port_admin_status_set(mlxsw_sp_port, false);
+       mlxsw_env_module_port_down(mlxsw_sp->core,
+                                  mlxsw_sp_port->mapping.module);
        return 0;
 }
 
@@ -1747,13 +1771,14 @@ err_port_label_info_get:
        mlxsw_sp_port_swid_set(mlxsw_sp, local_port,
                               MLXSW_PORT_SWID_DISABLED_PORT);
 err_port_swid_set:
-       mlxsw_sp_port_module_unmap(mlxsw_sp, local_port);
+       mlxsw_sp_port_module_unmap(mlxsw_sp, local_port, port_mapping->module);
        return err;
 }
 
 static void mlxsw_sp_port_remove(struct mlxsw_sp *mlxsw_sp, u8 local_port)
 {
        struct mlxsw_sp_port *mlxsw_sp_port = mlxsw_sp->ports[local_port];
+       u8 module = mlxsw_sp_port->mapping.module;
 
        cancel_delayed_work_sync(&mlxsw_sp_port->periodic_hw_stats.update_dw);
        cancel_delayed_work_sync(&mlxsw_sp_port->ptp.shaper_dw);
@@ -1775,7 +1800,7 @@ static void mlxsw_sp_port_remove(struct mlxsw_sp *mlxsw_sp, u8 local_port)
        mlxsw_core_port_fini(mlxsw_sp->core, local_port);
        mlxsw_sp_port_swid_set(mlxsw_sp, local_port,
                               MLXSW_PORT_SWID_DISABLED_PORT);
-       mlxsw_sp_port_module_unmap(mlxsw_sp, local_port);
+       mlxsw_sp_port_module_unmap(mlxsw_sp, local_port, module);
 }
 
 static int mlxsw_sp_cpu_port_create(struct mlxsw_sp *mlxsw_sp)