sonic-buildimage/platform/mellanox/non-upstream-patches/patches/0151-mlxsw-minimal-Prepare-driver-for-modular-system-supp.patch

496 lines
16 KiB
Diff

From 37eabf5ec0121c1a5092f48360b3d1208a22e655 Mon Sep 17 00:00:00 2001
From: Vadim Pasternak <vadimp@nvidia.com>
Date: Thu, 30 Dec 2021 16:02:59 +0000
Subject: [PATCH] mlxsw: minimal: Prepare driver for modular system support
As a preparation for line cards support:
- Allocate per line card array according to the queried number of slots
in the system. For each line card, allocate a port mapping array
according to the queried maximum number of ports available in system.
Port mapping array includes port object handle, local port number and
module number.
- Extend port creation APIs with 'slot_index' argument.
- Extend port structure with slot index and module offset for this slot
index.
For main board, slot will always be set to zero and these APIs will work
as before. For the ports located on line cards, slot should be set to the
physical slot number, where line card is located in modular systems.
Signed-off-by: Vadim Pasternak <vadimp@nvidia.com>
---
drivers/net/ethernet/mellanox/mlxsw/minimal.c | 293 +++++++++++++++---
1 file changed, 242 insertions(+), 51 deletions(-)
diff --git a/drivers/net/ethernet/mellanox/mlxsw/minimal.c b/drivers/net/ethernet/mellanox/mlxsw/minimal.c
index 30925f573..59c5053dc 100644
--- a/drivers/net/ethernet/mellanox/mlxsw/minimal.c
+++ b/drivers/net/ethernet/mellanox/mlxsw/minimal.c
@@ -24,22 +24,40 @@ static const struct mlxsw_fw_rev mlxsw_m_fw_rev = {
.subminor = MLXSW_M_FWREV_SUBMINOR,
};
+struct mlxsw_m_line_card;
struct mlxsw_m_port;
struct mlxsw_m {
- struct mlxsw_m_port **ports;
- int *module_to_port;
struct mlxsw_core *core;
const struct mlxsw_bus_info *bus_info;
u8 base_mac[ETH_ALEN];
u8 max_ports;
+ u8 max_module_count; /* Maximum number of modules per-slot. */
+ u8 num_of_slots; /* Including the main board. */
+ struct mlxsw_m_line_card **line_cards;
+};
+
+struct mlxsw_m_port_mapping {
+ struct mlxsw_m_port *port;
+ int module_to_port;
+ u8 module;
+};
+
+struct mlxsw_m_line_card {
+ struct mlxsw_m *mlxsw_m;
+ u8 max_ports;
+ u8 module_offset;
+ bool active;
+ struct mlxsw_m_port_mapping port_mapping[];
};
struct mlxsw_m_port {
struct net_device *dev;
struct mlxsw_m *mlxsw_m;
- u8 local_port;
+ u16 local_port;
u8 module;
+ u8 slot_index;
+ u8 module_offset;
};
static int mlxsw_m_base_mac_get(struct mlxsw_m *mlxsw_m)
@@ -111,8 +129,8 @@ static int mlxsw_m_get_module_info(struct net_device *netdev,
struct mlxsw_m_port *mlxsw_m_port = netdev_priv(netdev);
struct mlxsw_core *core = mlxsw_m_port->mlxsw_m->core;
- return mlxsw_env_get_module_info(core, 0, mlxsw_m_port->module,
- modinfo);
+ return mlxsw_env_get_module_info(core, mlxsw_m_port->slot_index,
+ mlxsw_m_port->module, modinfo);
}
static int
@@ -122,7 +140,8 @@ mlxsw_m_get_module_eeprom(struct net_device *netdev, struct ethtool_eeprom *ee,
struct mlxsw_m_port *mlxsw_m_port = netdev_priv(netdev);
struct mlxsw_core *core = mlxsw_m_port->mlxsw_m->core;
- return mlxsw_env_get_module_eeprom(netdev, core, 0,
+ return mlxsw_env_get_module_eeprom(netdev, core,
+ mlxsw_m_port->slot_index,
mlxsw_m_port->module, ee, data);
}
@@ -134,7 +153,8 @@ mlxsw_m_get_module_eeprom_by_page(struct net_device *netdev,
struct mlxsw_m_port *mlxsw_m_port = netdev_priv(netdev);
struct mlxsw_core *core = mlxsw_m_port->mlxsw_m->core;
- return mlxsw_env_get_module_eeprom_by_page(core, 0,
+ return mlxsw_env_get_module_eeprom_by_page(core,
+ mlxsw_m_port->slot_index,
mlxsw_m_port->module,
page, extack);
}
@@ -144,7 +164,8 @@ static int mlxsw_m_reset(struct net_device *netdev, u32 *flags)
struct mlxsw_m_port *mlxsw_m_port = netdev_priv(netdev);
struct mlxsw_core *core = mlxsw_m_port->mlxsw_m->core;
- return mlxsw_env_reset_module(netdev, core, 0, mlxsw_m_port->module,
+ return mlxsw_env_reset_module(netdev, core, mlxsw_m_port->slot_index,
+ mlxsw_m_port->module,
flags);
}
@@ -156,7 +177,8 @@ mlxsw_m_get_module_power_mode(struct net_device *netdev,
struct mlxsw_m_port *mlxsw_m_port = netdev_priv(netdev);
struct mlxsw_core *core = mlxsw_m_port->mlxsw_m->core;
- return mlxsw_env_get_module_power_mode(core, 0, mlxsw_m_port->module,
+ return mlxsw_env_get_module_power_mode(core, mlxsw_m_port->slot_index,
+ mlxsw_m_port->module,
params, extack);
}
@@ -168,7 +190,8 @@ mlxsw_m_set_module_power_mode(struct net_device *netdev,
struct mlxsw_m_port *mlxsw_m_port = netdev_priv(netdev);
struct mlxsw_core *core = mlxsw_m_port->mlxsw_m->core;
- return mlxsw_env_set_module_power_mode(core, 0, mlxsw_m_port->module,
+ return mlxsw_env_set_module_power_mode(core, mlxsw_m_port->slot_index,
+ mlxsw_m_port->module,
params->policy, extack);
}
@@ -199,19 +222,31 @@ mlxsw_m_port_dev_addr_get(struct mlxsw_m_port *mlxsw_m_port)
* to be such it does not overflow when adding local_port
* value.
*/
- dev->dev_addr[ETH_ALEN - 1] = mlxsw_m_port->module + 1;
+ dev->dev_addr[ETH_ALEN - 1] = mlxsw_m_port->module + 1 +
+ mlxsw_m_port->module_offset;
return 0;
}
+static struct
+mlxsw_m_port_mapping *mlxsw_m_port_mapping_get(struct mlxsw_m *mlxsw_m,
+ u8 slot_index, u8 local_port)
+{
+ return &mlxsw_m->line_cards[slot_index]->port_mapping[local_port];
+}
+
static int
-mlxsw_m_port_create(struct mlxsw_m *mlxsw_m, u8 local_port, u8 module)
+mlxsw_m_port_create(struct mlxsw_m *mlxsw_m, u8 slot_index, u16 local_port,
+ u8 module)
{
+ struct mlxsw_m_port_mapping *port_mapping;
struct mlxsw_m_port *mlxsw_m_port;
struct net_device *dev;
+ u8 module_offset;
int err;
- err = mlxsw_core_port_init(mlxsw_m->core, local_port, 0,
- module + 1, false, 0, false,
+ module_offset = mlxsw_m->line_cards[slot_index]->module_offset;
+ err = mlxsw_core_port_init(mlxsw_m->core, local_port, slot_index,
+ module + 1 + module_offset, false, 0, false,
0, mlxsw_m->base_mac,
sizeof(mlxsw_m->base_mac));
if (err) {
@@ -233,6 +268,13 @@ mlxsw_m_port_create(struct mlxsw_m *mlxsw_m, u8 local_port, u8 module)
mlxsw_m_port->mlxsw_m = mlxsw_m;
mlxsw_m_port->local_port = local_port;
mlxsw_m_port->module = module;
+ mlxsw_m_port->slot_index = slot_index;
+ /* Add module offset for line card. Offset for main board iz zero.
+ * For line card in slot #n offset is calculated as (#n - 1)
+ * multiplied by maximum modules number, which could be found on a line
+ * card.
+ */
+ mlxsw_m_port->module_offset = module_offset;
dev->netdev_ops = &mlxsw_m_port_netdev_ops;
dev->ethtool_ops = &mlxsw_m_port_ethtool_ops;
@@ -245,7 +287,9 @@ mlxsw_m_port_create(struct mlxsw_m *mlxsw_m, u8 local_port, u8 module)
}
netif_carrier_off(dev);
- mlxsw_m->ports[local_port] = mlxsw_m_port;
+ port_mapping = mlxsw_m_port_mapping_get(mlxsw_m, slot_index,
+ local_port);
+ port_mapping->port = mlxsw_m_port;
err = register_netdev(dev);
if (err) {
dev_err(mlxsw_m->bus_info->dev, "Port %d: Failed to register netdev\n",
@@ -259,7 +303,7 @@ mlxsw_m_port_create(struct mlxsw_m *mlxsw_m, u8 local_port, u8 module)
return 0;
err_register_netdev:
- mlxsw_m->ports[local_port] = NULL;
+ port_mapping->port = NULL;
err_dev_addr_get:
free_netdev(dev);
err_alloc_etherdev:
@@ -267,72 +311,130 @@ mlxsw_m_port_create(struct mlxsw_m *mlxsw_m, u8 local_port, u8 module)
return err;
}
-static void mlxsw_m_port_remove(struct mlxsw_m *mlxsw_m, u8 local_port)
+static void mlxsw_m_port_remove(struct mlxsw_m *mlxsw_m, u8 slot_index,
+ u16 local_port)
{
- struct mlxsw_m_port *mlxsw_m_port = mlxsw_m->ports[local_port];
+ struct mlxsw_m_port_mapping *port_mapping;
+ struct mlxsw_m_port *mlxsw_m_port;
+ port_mapping = mlxsw_m_port_mapping_get(mlxsw_m, slot_index,
+ local_port);
+ mlxsw_m_port = port_mapping->port;
mlxsw_core_port_clear(mlxsw_m->core, local_port, mlxsw_m);
unregister_netdev(mlxsw_m_port->dev); /* This calls ndo_stop */
- mlxsw_m->ports[local_port] = NULL;
+ port_mapping->port = NULL;
free_netdev(mlxsw_m_port->dev);
mlxsw_core_port_fini(mlxsw_m->core, local_port);
}
-static int mlxsw_m_ports_create(struct mlxsw_m *mlxsw_m)
+static int mlxsw_m_port_module_map(struct mlxsw_m *mlxsw_m, u8 slot_index,
+ u16 local_port, u8 module)
+{
+ struct mlxsw_m_port_mapping *port_mapping;
+
+ port_mapping = mlxsw_m_port_mapping_get(mlxsw_m, slot_index,
+ local_port);
+
+ if (WARN_ON_ONCE(port_mapping->module_to_port >= mlxsw_m->max_ports))
+ return -EINVAL;
+ mlxsw_env_module_port_map(mlxsw_m->core, slot_index, module);
+ port_mapping->module_to_port = local_port;
+ port_mapping->module = module;
+
+ return 0;
+}
+
+static void
+mlxsw_m_port_module_unmap(struct mlxsw_m *mlxsw_m, u8 slot_index,
+ struct mlxsw_m_port_mapping *port_mapping)
{
+ port_mapping->module_to_port = -1;
+ mlxsw_env_module_port_unmap(mlxsw_m->core, slot_index,
+ port_mapping->module);
+}
+
+static int mlxsw_m_ports_create(struct mlxsw_m *mlxsw_m, u8 slot_index)
+{
+ struct mlxsw_m_port_mapping *port_mapping;
+ struct mlxsw_m_line_card *line_card;
char mgpir_pl[MLXSW_REG_MGPIR_LEN];
int i, err;
- mlxsw_reg_mgpir_pack(mgpir_pl, 0);
+ mlxsw_reg_mgpir_pack(mgpir_pl, slot_index);
err = mlxsw_reg_query(mlxsw_m->core, MLXSW_REG(mgpir), mgpir_pl);
if (err)
return err;
+ line_card = mlxsw_m->line_cards[slot_index];
mlxsw_reg_mgpir_unpack(mgpir_pl, NULL, NULL, NULL,
- &mlxsw_m->max_ports, NULL);
- if (!mlxsw_m->max_ports)
+ &line_card->max_ports, NULL);
+ if (!line_card->max_ports)
return 0;
- mlxsw_m->ports = kcalloc(mlxsw_m->max_ports, sizeof(*mlxsw_m->ports),
- GFP_KERNEL);
- if (!mlxsw_m->ports)
- return -ENOMEM;
+ line_card->max_ports += 1;
+ line_card->module_offset = slot_index ? (slot_index - 1) *
+ mlxsw_m->max_module_count : 0;
- mlxsw_m->module_to_port = kmalloc_array(mlxsw_m->max_ports, sizeof(int),
- GFP_KERNEL);
- if (!mlxsw_m->module_to_port) {
- err = -ENOMEM;
- goto err_module_to_port_alloc;
+ /* Fill out module to local port mapping array */
+ for (i = 1; i < mlxsw_m->line_cards[slot_index]->max_ports; i++) {
+ err = mlxsw_m_port_module_map(mlxsw_m, slot_index, i +
+ line_card->module_offset, i - 1);
+ if (err)
+ goto err_module_to_port_map;
}
- /* Create port objects for each entry. */
+ /* Create port objects for each valid entry */
for (i = 0; i < mlxsw_m->max_ports; i++) {
- mlxsw_m->module_to_port[i] = i;
- err = mlxsw_m_port_create(mlxsw_m, mlxsw_m->module_to_port[i], i);
- if (err)
- goto err_module_to_port_create;
+ port_mapping = mlxsw_m_port_mapping_get(mlxsw_m, slot_index,
+ i);
+ if (port_mapping->module_to_port > 0) {
+ err = mlxsw_m_port_create(mlxsw_m, slot_index,
+ port_mapping->module_to_port,
+ port_mapping->module);
+ if (err)
+ goto err_module_to_port_create;
+ }
}
return 0;
err_module_to_port_create:
- for (i--; i >= 0; i--)
- mlxsw_m_port_remove(mlxsw_m, mlxsw_m->module_to_port[i]);
- kfree(mlxsw_m->module_to_port);
-err_module_to_port_alloc:
- kfree(mlxsw_m->ports);
+ for (i--; i >= 0; i--) {
+ port_mapping = mlxsw_m_port_mapping_get(mlxsw_m, slot_index,
+ i);
+ if (port_mapping->module_to_port > 0)
+ mlxsw_m_port_remove(mlxsw_m, slot_index,
+ port_mapping->module_to_port);
+ }
+ i = mlxsw_m->max_ports;
+err_module_to_port_map:
+ for (i--; i > 0; i--) {
+ port_mapping = mlxsw_m_port_mapping_get(mlxsw_m, slot_index,
+ i);
+ if (port_mapping->module_to_port > 0)
+ mlxsw_m_port_module_unmap(mlxsw_m, slot_index,
+ port_mapping);
+ }
return err;
}
-static void mlxsw_m_ports_remove(struct mlxsw_m *mlxsw_m)
+static void mlxsw_m_ports_remove(struct mlxsw_m *mlxsw_m, u8 slot_index)
{
+ struct mlxsw_m_port_mapping *port_mapping;
+ u8 module;
int i;
- for (i = 0; i < mlxsw_m->max_ports; i++)
- mlxsw_m_port_remove(mlxsw_m, mlxsw_m->module_to_port[i]);
-
- kfree(mlxsw_m->module_to_port);
- kfree(mlxsw_m->ports);
+ for (i = 0; i < mlxsw_m->max_ports; i++) {
+ port_mapping = mlxsw_m_port_mapping_get(mlxsw_m, slot_index,
+ i);
+ if (port_mapping->module_to_port > 0) {
+ module = port_mapping->port->module;
+ mlxsw_m_port_remove(mlxsw_m, slot_index,
+ port_mapping->module_to_port);
+ mlxsw_m_port_module_unmap(mlxsw_m, slot_index,
+ port_mapping);
+ }
+ }
}
static int mlxsw_m_fw_rev_validate(struct mlxsw_m *mlxsw_m)
@@ -353,6 +455,78 @@ static int mlxsw_m_fw_rev_validate(struct mlxsw_m *mlxsw_m)
return -EINVAL;
}
+static int mlxsw_m_get_peripheral_info(struct mlxsw_m *mlxsw_m)
+{
+ char mgpir_pl[MLXSW_REG_MGPIR_LEN];
+ u8 module_count;
+ int err;
+
+ mlxsw_reg_mgpir_pack(mgpir_pl, 0);
+ err = mlxsw_reg_query(mlxsw_m->core, MLXSW_REG(mgpir), mgpir_pl);
+ if (err)
+ return err;
+
+ mlxsw_reg_mgpir_unpack(mgpir_pl, NULL, NULL, NULL, &module_count,
+ &mlxsw_m->num_of_slots);
+ /* If the system is modular, get the maximum number of modules per-slot.
+ * Otherwise, get the maximum number of modules on the main board.
+ */
+ mlxsw_m->max_module_count = mlxsw_m->num_of_slots ?
+ mlxsw_reg_mgpir_max_modules_per_slot_get(mgpir_pl) :
+ module_count;
+ /* Add slot for main board. */
+ mlxsw_m->num_of_slots += 1;
+
+ return 0;
+}
+
+static int mlxsw_env_line_cards_alloc(struct mlxsw_m *mlxsw_m)
+{
+ unsigned int max_ports = mlxsw_core_max_ports(mlxsw_m->core);
+ struct mlxsw_m_port_mapping *port_mapping;
+ int i, j;
+
+ mlxsw_m->line_cards = kcalloc(mlxsw_m->num_of_slots,
+ sizeof(*mlxsw_m->line_cards),
+ GFP_KERNEL);
+ if (!mlxsw_m->line_cards)
+ goto err_kcalloc;
+
+ for (i = 0; i < mlxsw_m->num_of_slots; i++) {
+ mlxsw_m->line_cards[i] = kzalloc(struct_size(mlxsw_m->line_cards[i],
+ port_mapping, max_ports),
+ GFP_KERNEL);
+ if (!mlxsw_m->line_cards[i])
+ goto kzalloc_err;
+
+ /* Invalidate the entries of module to local port mapping array */
+ for (j = 0; j < mlxsw_m->max_ports; j++) {
+ port_mapping = mlxsw_m_port_mapping_get(mlxsw_m, i, j);
+ port_mapping->module_to_port = -1;
+ }
+ }
+
+ mlxsw_m->max_ports = max_ports;
+
+ return 0;
+
+kzalloc_err:
+ for (i--; i >= 0; i--)
+ kfree(mlxsw_m->line_cards[i]);
+err_kcalloc:
+ kfree(mlxsw_m->line_cards);
+ return -ENOMEM;
+}
+
+static void mlxsw_m_line_cards_free(struct mlxsw_m *mlxsw_m)
+{
+ int i = mlxsw_m->num_of_slots;
+
+ for (i--; i >= 0; i--)
+ kfree(mlxsw_m->line_cards[i]);
+ kfree(mlxsw_m->line_cards);
+}
+
static int mlxsw_m_init(struct mlxsw_core *mlxsw_core,
const struct mlxsw_bus_info *mlxsw_bus_info,
struct netlink_ext_ack *extack)
@@ -367,26 +541,43 @@ static int mlxsw_m_init(struct mlxsw_core *mlxsw_core,
if (err)
return err;
+ err = mlxsw_m_get_peripheral_info(mlxsw_m);
+ if (err) {
+ dev_err(mlxsw_m->bus_info->dev, "Failed to get peripheral info\n");
+ return err;
+ }
+
err = mlxsw_m_base_mac_get(mlxsw_m);
if (err) {
dev_err(mlxsw_m->bus_info->dev, "Failed to get base mac\n");
return err;
}
- err = mlxsw_m_ports_create(mlxsw_m);
+ err = mlxsw_env_line_cards_alloc(mlxsw_m);
if (err) {
- dev_err(mlxsw_m->bus_info->dev, "Failed to create ports\n");
+ dev_err(mlxsw_m->bus_info->dev, "Failed to allocate memory\n");
return err;
}
+ err = mlxsw_m_ports_create(mlxsw_m, 0);
+ if (err) {
+ dev_err(mlxsw_m->bus_info->dev, "Failed to create ports\n");
+ goto err_mlxsw_m_ports_create;
+ }
+
return 0;
+
+err_mlxsw_m_ports_create:
+ mlxsw_m_line_cards_free(mlxsw_m);
+ return err;
}
static void mlxsw_m_fini(struct mlxsw_core *mlxsw_core)
{
struct mlxsw_m *mlxsw_m = mlxsw_core_driver_priv(mlxsw_core);
- mlxsw_m_ports_remove(mlxsw_m);
+ mlxsw_m_ports_remove(mlxsw_m, 0);
+ mlxsw_m_line_cards_free(mlxsw_m);
}
static const struct mlxsw_config_profile mlxsw_m_config_profile;
--
2.30.2