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 543f401cb5c6a335c0878ed8000b4eee124b901c..c7b7254061ee3a1616b7d2772e463087f9a8682c 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 0bf5bd0f8a7ee18aaf3072e6ecf67122a67dc6d1..ba9269f12cb8c443b3baff3a1ec0b15c8a5a64e0 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 d9d56c44e994fdc80bf22d5c9c601c38510888e0..a3eca0b56bbef775ef9b69b81442f9753ea854c4 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 cea411884b054d5e0faa0b31294d7ad2838a1bfd..0e81ae723bc8583bf0eefc852fa77626e4f6aac8 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)