162306a36Sopenharmony_ci// SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0 262306a36Sopenharmony_ci/* Copyright (c) 2016-2019 Mellanox Technologies. All rights reserved */ 362306a36Sopenharmony_ci 462306a36Sopenharmony_ci#include <linux/netdevice.h> 562306a36Sopenharmony_ci#include <linux/etherdevice.h> 662306a36Sopenharmony_ci#include <linux/ethtool.h> 762306a36Sopenharmony_ci#include <linux/i2c.h> 862306a36Sopenharmony_ci#include <linux/kernel.h> 962306a36Sopenharmony_ci#include <linux/module.h> 1062306a36Sopenharmony_ci#include <linux/mod_devicetable.h> 1162306a36Sopenharmony_ci#include <linux/types.h> 1262306a36Sopenharmony_ci 1362306a36Sopenharmony_ci#include "core.h" 1462306a36Sopenharmony_ci#include "core_env.h" 1562306a36Sopenharmony_ci#include "i2c.h" 1662306a36Sopenharmony_ci 1762306a36Sopenharmony_cistatic const char mlxsw_m_driver_name[] = "mlxsw_minimal"; 1862306a36Sopenharmony_ci 1962306a36Sopenharmony_ci#define MLXSW_M_FWREV_MINOR 2000 2062306a36Sopenharmony_ci#define MLXSW_M_FWREV_SUBMINOR 1886 2162306a36Sopenharmony_ci 2262306a36Sopenharmony_cistatic const struct mlxsw_fw_rev mlxsw_m_fw_rev = { 2362306a36Sopenharmony_ci .minor = MLXSW_M_FWREV_MINOR, 2462306a36Sopenharmony_ci .subminor = MLXSW_M_FWREV_SUBMINOR, 2562306a36Sopenharmony_ci}; 2662306a36Sopenharmony_ci 2762306a36Sopenharmony_cistruct mlxsw_m_port; 2862306a36Sopenharmony_ci 2962306a36Sopenharmony_cistruct mlxsw_m_line_card { 3062306a36Sopenharmony_ci bool active; 3162306a36Sopenharmony_ci int module_to_port[]; 3262306a36Sopenharmony_ci}; 3362306a36Sopenharmony_ci 3462306a36Sopenharmony_cistruct mlxsw_m { 3562306a36Sopenharmony_ci struct mlxsw_m_port **ports; 3662306a36Sopenharmony_ci struct mlxsw_core *core; 3762306a36Sopenharmony_ci const struct mlxsw_bus_info *bus_info; 3862306a36Sopenharmony_ci u8 base_mac[ETH_ALEN]; 3962306a36Sopenharmony_ci u8 max_ports; 4062306a36Sopenharmony_ci u8 max_modules_per_slot; /* Maximum number of modules per-slot. */ 4162306a36Sopenharmony_ci u8 num_of_slots; /* Including the main board. */ 4262306a36Sopenharmony_ci struct mlxsw_m_line_card **line_cards; 4362306a36Sopenharmony_ci}; 4462306a36Sopenharmony_ci 4562306a36Sopenharmony_cistruct mlxsw_m_port { 4662306a36Sopenharmony_ci struct net_device *dev; 4762306a36Sopenharmony_ci struct mlxsw_m *mlxsw_m; 4862306a36Sopenharmony_ci u16 local_port; 4962306a36Sopenharmony_ci u8 slot_index; 5062306a36Sopenharmony_ci u8 module; 5162306a36Sopenharmony_ci u8 module_offset; 5262306a36Sopenharmony_ci}; 5362306a36Sopenharmony_ci 5462306a36Sopenharmony_cistatic int mlxsw_m_base_mac_get(struct mlxsw_m *mlxsw_m) 5562306a36Sopenharmony_ci{ 5662306a36Sopenharmony_ci char spad_pl[MLXSW_REG_SPAD_LEN] = {0}; 5762306a36Sopenharmony_ci int err; 5862306a36Sopenharmony_ci 5962306a36Sopenharmony_ci err = mlxsw_reg_query(mlxsw_m->core, MLXSW_REG(spad), spad_pl); 6062306a36Sopenharmony_ci if (err) 6162306a36Sopenharmony_ci return err; 6262306a36Sopenharmony_ci mlxsw_reg_spad_base_mac_memcpy_from(spad_pl, mlxsw_m->base_mac); 6362306a36Sopenharmony_ci return 0; 6462306a36Sopenharmony_ci} 6562306a36Sopenharmony_ci 6662306a36Sopenharmony_cistatic int mlxsw_m_port_open(struct net_device *dev) 6762306a36Sopenharmony_ci{ 6862306a36Sopenharmony_ci struct mlxsw_m_port *mlxsw_m_port = netdev_priv(dev); 6962306a36Sopenharmony_ci struct mlxsw_m *mlxsw_m = mlxsw_m_port->mlxsw_m; 7062306a36Sopenharmony_ci 7162306a36Sopenharmony_ci return mlxsw_env_module_port_up(mlxsw_m->core, 0, 7262306a36Sopenharmony_ci mlxsw_m_port->module); 7362306a36Sopenharmony_ci} 7462306a36Sopenharmony_ci 7562306a36Sopenharmony_cistatic int mlxsw_m_port_stop(struct net_device *dev) 7662306a36Sopenharmony_ci{ 7762306a36Sopenharmony_ci struct mlxsw_m_port *mlxsw_m_port = netdev_priv(dev); 7862306a36Sopenharmony_ci struct mlxsw_m *mlxsw_m = mlxsw_m_port->mlxsw_m; 7962306a36Sopenharmony_ci 8062306a36Sopenharmony_ci mlxsw_env_module_port_down(mlxsw_m->core, 0, mlxsw_m_port->module); 8162306a36Sopenharmony_ci return 0; 8262306a36Sopenharmony_ci} 8362306a36Sopenharmony_ci 8462306a36Sopenharmony_cistatic const struct net_device_ops mlxsw_m_port_netdev_ops = { 8562306a36Sopenharmony_ci .ndo_open = mlxsw_m_port_open, 8662306a36Sopenharmony_ci .ndo_stop = mlxsw_m_port_stop, 8762306a36Sopenharmony_ci}; 8862306a36Sopenharmony_ci 8962306a36Sopenharmony_cistatic void mlxsw_m_module_get_drvinfo(struct net_device *dev, 9062306a36Sopenharmony_ci struct ethtool_drvinfo *drvinfo) 9162306a36Sopenharmony_ci{ 9262306a36Sopenharmony_ci struct mlxsw_m_port *mlxsw_m_port = netdev_priv(dev); 9362306a36Sopenharmony_ci struct mlxsw_m *mlxsw_m = mlxsw_m_port->mlxsw_m; 9462306a36Sopenharmony_ci 9562306a36Sopenharmony_ci strscpy(drvinfo->driver, mlxsw_m->bus_info->device_kind, 9662306a36Sopenharmony_ci sizeof(drvinfo->driver)); 9762306a36Sopenharmony_ci snprintf(drvinfo->fw_version, sizeof(drvinfo->fw_version), 9862306a36Sopenharmony_ci "%d.%d.%d", 9962306a36Sopenharmony_ci mlxsw_m->bus_info->fw_rev.major, 10062306a36Sopenharmony_ci mlxsw_m->bus_info->fw_rev.minor, 10162306a36Sopenharmony_ci mlxsw_m->bus_info->fw_rev.subminor); 10262306a36Sopenharmony_ci strscpy(drvinfo->bus_info, mlxsw_m->bus_info->device_name, 10362306a36Sopenharmony_ci sizeof(drvinfo->bus_info)); 10462306a36Sopenharmony_ci} 10562306a36Sopenharmony_ci 10662306a36Sopenharmony_cistatic int mlxsw_m_get_module_info(struct net_device *netdev, 10762306a36Sopenharmony_ci struct ethtool_modinfo *modinfo) 10862306a36Sopenharmony_ci{ 10962306a36Sopenharmony_ci struct mlxsw_m_port *mlxsw_m_port = netdev_priv(netdev); 11062306a36Sopenharmony_ci struct mlxsw_core *core = mlxsw_m_port->mlxsw_m->core; 11162306a36Sopenharmony_ci 11262306a36Sopenharmony_ci return mlxsw_env_get_module_info(netdev, core, 11362306a36Sopenharmony_ci mlxsw_m_port->slot_index, 11462306a36Sopenharmony_ci mlxsw_m_port->module, modinfo); 11562306a36Sopenharmony_ci} 11662306a36Sopenharmony_ci 11762306a36Sopenharmony_cistatic int 11862306a36Sopenharmony_cimlxsw_m_get_module_eeprom(struct net_device *netdev, struct ethtool_eeprom *ee, 11962306a36Sopenharmony_ci u8 *data) 12062306a36Sopenharmony_ci{ 12162306a36Sopenharmony_ci struct mlxsw_m_port *mlxsw_m_port = netdev_priv(netdev); 12262306a36Sopenharmony_ci struct mlxsw_core *core = mlxsw_m_port->mlxsw_m->core; 12362306a36Sopenharmony_ci 12462306a36Sopenharmony_ci return mlxsw_env_get_module_eeprom(netdev, core, 12562306a36Sopenharmony_ci mlxsw_m_port->slot_index, 12662306a36Sopenharmony_ci mlxsw_m_port->module, ee, data); 12762306a36Sopenharmony_ci} 12862306a36Sopenharmony_ci 12962306a36Sopenharmony_cistatic int 13062306a36Sopenharmony_cimlxsw_m_get_module_eeprom_by_page(struct net_device *netdev, 13162306a36Sopenharmony_ci const struct ethtool_module_eeprom *page, 13262306a36Sopenharmony_ci struct netlink_ext_ack *extack) 13362306a36Sopenharmony_ci{ 13462306a36Sopenharmony_ci struct mlxsw_m_port *mlxsw_m_port = netdev_priv(netdev); 13562306a36Sopenharmony_ci struct mlxsw_core *core = mlxsw_m_port->mlxsw_m->core; 13662306a36Sopenharmony_ci 13762306a36Sopenharmony_ci return mlxsw_env_get_module_eeprom_by_page(core, 13862306a36Sopenharmony_ci mlxsw_m_port->slot_index, 13962306a36Sopenharmony_ci mlxsw_m_port->module, 14062306a36Sopenharmony_ci page, extack); 14162306a36Sopenharmony_ci} 14262306a36Sopenharmony_ci 14362306a36Sopenharmony_cistatic int mlxsw_m_reset(struct net_device *netdev, u32 *flags) 14462306a36Sopenharmony_ci{ 14562306a36Sopenharmony_ci struct mlxsw_m_port *mlxsw_m_port = netdev_priv(netdev); 14662306a36Sopenharmony_ci struct mlxsw_core *core = mlxsw_m_port->mlxsw_m->core; 14762306a36Sopenharmony_ci 14862306a36Sopenharmony_ci return mlxsw_env_reset_module(netdev, core, mlxsw_m_port->slot_index, 14962306a36Sopenharmony_ci mlxsw_m_port->module, 15062306a36Sopenharmony_ci flags); 15162306a36Sopenharmony_ci} 15262306a36Sopenharmony_ci 15362306a36Sopenharmony_cistatic int 15462306a36Sopenharmony_cimlxsw_m_get_module_power_mode(struct net_device *netdev, 15562306a36Sopenharmony_ci struct ethtool_module_power_mode_params *params, 15662306a36Sopenharmony_ci struct netlink_ext_ack *extack) 15762306a36Sopenharmony_ci{ 15862306a36Sopenharmony_ci struct mlxsw_m_port *mlxsw_m_port = netdev_priv(netdev); 15962306a36Sopenharmony_ci struct mlxsw_core *core = mlxsw_m_port->mlxsw_m->core; 16062306a36Sopenharmony_ci 16162306a36Sopenharmony_ci return mlxsw_env_get_module_power_mode(core, mlxsw_m_port->slot_index, 16262306a36Sopenharmony_ci mlxsw_m_port->module, 16362306a36Sopenharmony_ci params, extack); 16462306a36Sopenharmony_ci} 16562306a36Sopenharmony_ci 16662306a36Sopenharmony_cistatic int 16762306a36Sopenharmony_cimlxsw_m_set_module_power_mode(struct net_device *netdev, 16862306a36Sopenharmony_ci const struct ethtool_module_power_mode_params *params, 16962306a36Sopenharmony_ci struct netlink_ext_ack *extack) 17062306a36Sopenharmony_ci{ 17162306a36Sopenharmony_ci struct mlxsw_m_port *mlxsw_m_port = netdev_priv(netdev); 17262306a36Sopenharmony_ci struct mlxsw_core *core = mlxsw_m_port->mlxsw_m->core; 17362306a36Sopenharmony_ci 17462306a36Sopenharmony_ci return mlxsw_env_set_module_power_mode(core, mlxsw_m_port->slot_index, 17562306a36Sopenharmony_ci mlxsw_m_port->module, 17662306a36Sopenharmony_ci params->policy, extack); 17762306a36Sopenharmony_ci} 17862306a36Sopenharmony_ci 17962306a36Sopenharmony_cistatic const struct ethtool_ops mlxsw_m_port_ethtool_ops = { 18062306a36Sopenharmony_ci .get_drvinfo = mlxsw_m_module_get_drvinfo, 18162306a36Sopenharmony_ci .get_module_info = mlxsw_m_get_module_info, 18262306a36Sopenharmony_ci .get_module_eeprom = mlxsw_m_get_module_eeprom, 18362306a36Sopenharmony_ci .get_module_eeprom_by_page = mlxsw_m_get_module_eeprom_by_page, 18462306a36Sopenharmony_ci .reset = mlxsw_m_reset, 18562306a36Sopenharmony_ci .get_module_power_mode = mlxsw_m_get_module_power_mode, 18662306a36Sopenharmony_ci .set_module_power_mode = mlxsw_m_set_module_power_mode, 18762306a36Sopenharmony_ci}; 18862306a36Sopenharmony_ci 18962306a36Sopenharmony_cistatic int 19062306a36Sopenharmony_cimlxsw_m_port_module_info_get(struct mlxsw_m *mlxsw_m, u16 local_port, 19162306a36Sopenharmony_ci u8 *p_module, u8 *p_width, u8 *p_slot_index) 19262306a36Sopenharmony_ci{ 19362306a36Sopenharmony_ci char pmlp_pl[MLXSW_REG_PMLP_LEN]; 19462306a36Sopenharmony_ci int err; 19562306a36Sopenharmony_ci 19662306a36Sopenharmony_ci mlxsw_reg_pmlp_pack(pmlp_pl, local_port); 19762306a36Sopenharmony_ci err = mlxsw_reg_query(mlxsw_m->core, MLXSW_REG(pmlp), pmlp_pl); 19862306a36Sopenharmony_ci if (err) 19962306a36Sopenharmony_ci return err; 20062306a36Sopenharmony_ci *p_module = mlxsw_reg_pmlp_module_get(pmlp_pl, 0); 20162306a36Sopenharmony_ci *p_width = mlxsw_reg_pmlp_width_get(pmlp_pl); 20262306a36Sopenharmony_ci *p_slot_index = mlxsw_reg_pmlp_slot_index_get(pmlp_pl, 0); 20362306a36Sopenharmony_ci 20462306a36Sopenharmony_ci return 0; 20562306a36Sopenharmony_ci} 20662306a36Sopenharmony_ci 20762306a36Sopenharmony_cistatic int 20862306a36Sopenharmony_cimlxsw_m_port_dev_addr_get(struct mlxsw_m_port *mlxsw_m_port) 20962306a36Sopenharmony_ci{ 21062306a36Sopenharmony_ci struct mlxsw_m *mlxsw_m = mlxsw_m_port->mlxsw_m; 21162306a36Sopenharmony_ci char ppad_pl[MLXSW_REG_PPAD_LEN]; 21262306a36Sopenharmony_ci u8 addr[ETH_ALEN]; 21362306a36Sopenharmony_ci int err; 21462306a36Sopenharmony_ci 21562306a36Sopenharmony_ci mlxsw_reg_ppad_pack(ppad_pl, false, 0); 21662306a36Sopenharmony_ci err = mlxsw_reg_query(mlxsw_m->core, MLXSW_REG(ppad), ppad_pl); 21762306a36Sopenharmony_ci if (err) 21862306a36Sopenharmony_ci return err; 21962306a36Sopenharmony_ci mlxsw_reg_ppad_mac_memcpy_from(ppad_pl, addr); 22062306a36Sopenharmony_ci eth_hw_addr_gen(mlxsw_m_port->dev, addr, mlxsw_m_port->module + 1 + 22162306a36Sopenharmony_ci mlxsw_m_port->module_offset); 22262306a36Sopenharmony_ci return 0; 22362306a36Sopenharmony_ci} 22462306a36Sopenharmony_ci 22562306a36Sopenharmony_cistatic bool mlxsw_m_port_created(struct mlxsw_m *mlxsw_m, u16 local_port) 22662306a36Sopenharmony_ci{ 22762306a36Sopenharmony_ci return mlxsw_m->ports[local_port]; 22862306a36Sopenharmony_ci} 22962306a36Sopenharmony_ci 23062306a36Sopenharmony_cistatic int 23162306a36Sopenharmony_cimlxsw_m_port_create(struct mlxsw_m *mlxsw_m, u16 local_port, u8 slot_index, 23262306a36Sopenharmony_ci u8 module) 23362306a36Sopenharmony_ci{ 23462306a36Sopenharmony_ci struct mlxsw_m_port *mlxsw_m_port; 23562306a36Sopenharmony_ci struct net_device *dev; 23662306a36Sopenharmony_ci int err; 23762306a36Sopenharmony_ci 23862306a36Sopenharmony_ci err = mlxsw_core_port_init(mlxsw_m->core, local_port, slot_index, 23962306a36Sopenharmony_ci module + 1, false, 0, false, 24062306a36Sopenharmony_ci 0, mlxsw_m->base_mac, 24162306a36Sopenharmony_ci sizeof(mlxsw_m->base_mac)); 24262306a36Sopenharmony_ci if (err) { 24362306a36Sopenharmony_ci dev_err(mlxsw_m->bus_info->dev, "Port %d: Failed to init core port\n", 24462306a36Sopenharmony_ci local_port); 24562306a36Sopenharmony_ci return err; 24662306a36Sopenharmony_ci } 24762306a36Sopenharmony_ci 24862306a36Sopenharmony_ci dev = alloc_etherdev(sizeof(struct mlxsw_m_port)); 24962306a36Sopenharmony_ci if (!dev) { 25062306a36Sopenharmony_ci err = -ENOMEM; 25162306a36Sopenharmony_ci goto err_alloc_etherdev; 25262306a36Sopenharmony_ci } 25362306a36Sopenharmony_ci 25462306a36Sopenharmony_ci SET_NETDEV_DEV(dev, mlxsw_m->bus_info->dev); 25562306a36Sopenharmony_ci dev_net_set(dev, mlxsw_core_net(mlxsw_m->core)); 25662306a36Sopenharmony_ci mlxsw_m_port = netdev_priv(dev); 25762306a36Sopenharmony_ci mlxsw_core_port_netdev_link(mlxsw_m->core, local_port, 25862306a36Sopenharmony_ci mlxsw_m_port, dev); 25962306a36Sopenharmony_ci mlxsw_m_port->dev = dev; 26062306a36Sopenharmony_ci mlxsw_m_port->mlxsw_m = mlxsw_m; 26162306a36Sopenharmony_ci mlxsw_m_port->local_port = local_port; 26262306a36Sopenharmony_ci mlxsw_m_port->module = module; 26362306a36Sopenharmony_ci mlxsw_m_port->slot_index = slot_index; 26462306a36Sopenharmony_ci /* Add module offset for line card. Offset for main board iz zero. 26562306a36Sopenharmony_ci * For line card in slot #n offset is calculated as (#n - 1) 26662306a36Sopenharmony_ci * multiplied by maximum modules number, which could be found on a line 26762306a36Sopenharmony_ci * card. 26862306a36Sopenharmony_ci */ 26962306a36Sopenharmony_ci mlxsw_m_port->module_offset = mlxsw_m_port->slot_index ? 27062306a36Sopenharmony_ci (mlxsw_m_port->slot_index - 1) * 27162306a36Sopenharmony_ci mlxsw_m->max_modules_per_slot : 0; 27262306a36Sopenharmony_ci 27362306a36Sopenharmony_ci dev->netdev_ops = &mlxsw_m_port_netdev_ops; 27462306a36Sopenharmony_ci dev->ethtool_ops = &mlxsw_m_port_ethtool_ops; 27562306a36Sopenharmony_ci 27662306a36Sopenharmony_ci err = mlxsw_m_port_dev_addr_get(mlxsw_m_port); 27762306a36Sopenharmony_ci if (err) { 27862306a36Sopenharmony_ci dev_err(mlxsw_m->bus_info->dev, "Port %d: Unable to get port mac address\n", 27962306a36Sopenharmony_ci mlxsw_m_port->local_port); 28062306a36Sopenharmony_ci goto err_dev_addr_get; 28162306a36Sopenharmony_ci } 28262306a36Sopenharmony_ci 28362306a36Sopenharmony_ci netif_carrier_off(dev); 28462306a36Sopenharmony_ci mlxsw_m->ports[local_port] = mlxsw_m_port; 28562306a36Sopenharmony_ci err = register_netdev(dev); 28662306a36Sopenharmony_ci if (err) { 28762306a36Sopenharmony_ci dev_err(mlxsw_m->bus_info->dev, "Port %d: Failed to register netdev\n", 28862306a36Sopenharmony_ci mlxsw_m_port->local_port); 28962306a36Sopenharmony_ci goto err_register_netdev; 29062306a36Sopenharmony_ci } 29162306a36Sopenharmony_ci 29262306a36Sopenharmony_ci return 0; 29362306a36Sopenharmony_ci 29462306a36Sopenharmony_cierr_register_netdev: 29562306a36Sopenharmony_ci mlxsw_m->ports[local_port] = NULL; 29662306a36Sopenharmony_cierr_dev_addr_get: 29762306a36Sopenharmony_ci free_netdev(dev); 29862306a36Sopenharmony_cierr_alloc_etherdev: 29962306a36Sopenharmony_ci mlxsw_core_port_fini(mlxsw_m->core, local_port); 30062306a36Sopenharmony_ci return err; 30162306a36Sopenharmony_ci} 30262306a36Sopenharmony_ci 30362306a36Sopenharmony_cistatic void mlxsw_m_port_remove(struct mlxsw_m *mlxsw_m, u16 local_port) 30462306a36Sopenharmony_ci{ 30562306a36Sopenharmony_ci struct mlxsw_m_port *mlxsw_m_port = mlxsw_m->ports[local_port]; 30662306a36Sopenharmony_ci 30762306a36Sopenharmony_ci unregister_netdev(mlxsw_m_port->dev); /* This calls ndo_stop */ 30862306a36Sopenharmony_ci mlxsw_m->ports[local_port] = NULL; 30962306a36Sopenharmony_ci free_netdev(mlxsw_m_port->dev); 31062306a36Sopenharmony_ci mlxsw_core_port_fini(mlxsw_m->core, local_port); 31162306a36Sopenharmony_ci} 31262306a36Sopenharmony_ci 31362306a36Sopenharmony_cistatic int* 31462306a36Sopenharmony_cimlxsw_m_port_mapping_get(struct mlxsw_m *mlxsw_m, u8 slot_index, u8 module) 31562306a36Sopenharmony_ci{ 31662306a36Sopenharmony_ci return &mlxsw_m->line_cards[slot_index]->module_to_port[module]; 31762306a36Sopenharmony_ci} 31862306a36Sopenharmony_ci 31962306a36Sopenharmony_cistatic int mlxsw_m_port_module_map(struct mlxsw_m *mlxsw_m, u16 local_port, 32062306a36Sopenharmony_ci u8 *last_module) 32162306a36Sopenharmony_ci{ 32262306a36Sopenharmony_ci unsigned int max_ports = mlxsw_core_max_ports(mlxsw_m->core); 32362306a36Sopenharmony_ci u8 module, width, slot_index; 32462306a36Sopenharmony_ci int *module_to_port; 32562306a36Sopenharmony_ci int err; 32662306a36Sopenharmony_ci 32762306a36Sopenharmony_ci /* Fill out to local port mapping array */ 32862306a36Sopenharmony_ci err = mlxsw_m_port_module_info_get(mlxsw_m, local_port, &module, 32962306a36Sopenharmony_ci &width, &slot_index); 33062306a36Sopenharmony_ci if (err) 33162306a36Sopenharmony_ci return err; 33262306a36Sopenharmony_ci 33362306a36Sopenharmony_ci /* Skip if line card has been already configured */ 33462306a36Sopenharmony_ci if (mlxsw_m->line_cards[slot_index]->active) 33562306a36Sopenharmony_ci return 0; 33662306a36Sopenharmony_ci if (!width) 33762306a36Sopenharmony_ci return 0; 33862306a36Sopenharmony_ci /* Skip, if port belongs to the cluster */ 33962306a36Sopenharmony_ci if (module == *last_module) 34062306a36Sopenharmony_ci return 0; 34162306a36Sopenharmony_ci *last_module = module; 34262306a36Sopenharmony_ci 34362306a36Sopenharmony_ci if (WARN_ON_ONCE(module >= max_ports)) 34462306a36Sopenharmony_ci return -EINVAL; 34562306a36Sopenharmony_ci mlxsw_env_module_port_map(mlxsw_m->core, slot_index, module); 34662306a36Sopenharmony_ci module_to_port = mlxsw_m_port_mapping_get(mlxsw_m, slot_index, module); 34762306a36Sopenharmony_ci *module_to_port = local_port; 34862306a36Sopenharmony_ci 34962306a36Sopenharmony_ci return 0; 35062306a36Sopenharmony_ci} 35162306a36Sopenharmony_ci 35262306a36Sopenharmony_cistatic void 35362306a36Sopenharmony_cimlxsw_m_port_module_unmap(struct mlxsw_m *mlxsw_m, u8 slot_index, u8 module) 35462306a36Sopenharmony_ci{ 35562306a36Sopenharmony_ci int *module_to_port = mlxsw_m_port_mapping_get(mlxsw_m, slot_index, 35662306a36Sopenharmony_ci module); 35762306a36Sopenharmony_ci *module_to_port = -1; 35862306a36Sopenharmony_ci mlxsw_env_module_port_unmap(mlxsw_m->core, slot_index, module); 35962306a36Sopenharmony_ci} 36062306a36Sopenharmony_ci 36162306a36Sopenharmony_cistatic int mlxsw_m_linecards_init(struct mlxsw_m *mlxsw_m) 36262306a36Sopenharmony_ci{ 36362306a36Sopenharmony_ci unsigned int max_ports = mlxsw_core_max_ports(mlxsw_m->core); 36462306a36Sopenharmony_ci char mgpir_pl[MLXSW_REG_MGPIR_LEN]; 36562306a36Sopenharmony_ci u8 num_of_modules; 36662306a36Sopenharmony_ci int i, j, err; 36762306a36Sopenharmony_ci 36862306a36Sopenharmony_ci mlxsw_reg_mgpir_pack(mgpir_pl, 0); 36962306a36Sopenharmony_ci err = mlxsw_reg_query(mlxsw_m->core, MLXSW_REG(mgpir), mgpir_pl); 37062306a36Sopenharmony_ci if (err) 37162306a36Sopenharmony_ci return err; 37262306a36Sopenharmony_ci 37362306a36Sopenharmony_ci mlxsw_reg_mgpir_unpack(mgpir_pl, NULL, NULL, NULL, &num_of_modules, 37462306a36Sopenharmony_ci &mlxsw_m->num_of_slots); 37562306a36Sopenharmony_ci /* If the system is modular, get the maximum number of modules per-slot. 37662306a36Sopenharmony_ci * Otherwise, get the maximum number of modules on the main board. 37762306a36Sopenharmony_ci */ 37862306a36Sopenharmony_ci if (mlxsw_m->num_of_slots) 37962306a36Sopenharmony_ci mlxsw_m->max_modules_per_slot = 38062306a36Sopenharmony_ci mlxsw_reg_mgpir_max_modules_per_slot_get(mgpir_pl); 38162306a36Sopenharmony_ci else 38262306a36Sopenharmony_ci mlxsw_m->max_modules_per_slot = num_of_modules; 38362306a36Sopenharmony_ci /* Add slot for main board. */ 38462306a36Sopenharmony_ci mlxsw_m->num_of_slots += 1; 38562306a36Sopenharmony_ci 38662306a36Sopenharmony_ci mlxsw_m->ports = kcalloc(max_ports, sizeof(*mlxsw_m->ports), 38762306a36Sopenharmony_ci GFP_KERNEL); 38862306a36Sopenharmony_ci if (!mlxsw_m->ports) 38962306a36Sopenharmony_ci return -ENOMEM; 39062306a36Sopenharmony_ci 39162306a36Sopenharmony_ci mlxsw_m->line_cards = kcalloc(mlxsw_m->num_of_slots, 39262306a36Sopenharmony_ci sizeof(*mlxsw_m->line_cards), 39362306a36Sopenharmony_ci GFP_KERNEL); 39462306a36Sopenharmony_ci if (!mlxsw_m->line_cards) { 39562306a36Sopenharmony_ci err = -ENOMEM; 39662306a36Sopenharmony_ci goto err_kcalloc; 39762306a36Sopenharmony_ci } 39862306a36Sopenharmony_ci 39962306a36Sopenharmony_ci for (i = 0; i < mlxsw_m->num_of_slots; i++) { 40062306a36Sopenharmony_ci mlxsw_m->line_cards[i] = 40162306a36Sopenharmony_ci kzalloc(struct_size(mlxsw_m->line_cards[i], 40262306a36Sopenharmony_ci module_to_port, 40362306a36Sopenharmony_ci mlxsw_m->max_modules_per_slot), 40462306a36Sopenharmony_ci GFP_KERNEL); 40562306a36Sopenharmony_ci if (!mlxsw_m->line_cards[i]) { 40662306a36Sopenharmony_ci err = -ENOMEM; 40762306a36Sopenharmony_ci goto err_kmalloc_array; 40862306a36Sopenharmony_ci } 40962306a36Sopenharmony_ci 41062306a36Sopenharmony_ci /* Invalidate the entries of module to local port mapping array. */ 41162306a36Sopenharmony_ci for (j = 0; j < mlxsw_m->max_modules_per_slot; j++) 41262306a36Sopenharmony_ci mlxsw_m->line_cards[i]->module_to_port[j] = -1; 41362306a36Sopenharmony_ci } 41462306a36Sopenharmony_ci 41562306a36Sopenharmony_ci return 0; 41662306a36Sopenharmony_ci 41762306a36Sopenharmony_cierr_kmalloc_array: 41862306a36Sopenharmony_ci for (i--; i >= 0; i--) 41962306a36Sopenharmony_ci kfree(mlxsw_m->line_cards[i]); 42062306a36Sopenharmony_ci kfree(mlxsw_m->line_cards); 42162306a36Sopenharmony_cierr_kcalloc: 42262306a36Sopenharmony_ci kfree(mlxsw_m->ports); 42362306a36Sopenharmony_ci return err; 42462306a36Sopenharmony_ci} 42562306a36Sopenharmony_ci 42662306a36Sopenharmony_cistatic void mlxsw_m_linecards_fini(struct mlxsw_m *mlxsw_m) 42762306a36Sopenharmony_ci{ 42862306a36Sopenharmony_ci int i = mlxsw_m->num_of_slots; 42962306a36Sopenharmony_ci 43062306a36Sopenharmony_ci for (i--; i >= 0; i--) 43162306a36Sopenharmony_ci kfree(mlxsw_m->line_cards[i]); 43262306a36Sopenharmony_ci kfree(mlxsw_m->line_cards); 43362306a36Sopenharmony_ci kfree(mlxsw_m->ports); 43462306a36Sopenharmony_ci} 43562306a36Sopenharmony_ci 43662306a36Sopenharmony_cistatic void 43762306a36Sopenharmony_cimlxsw_m_linecard_port_module_unmap(struct mlxsw_m *mlxsw_m, u8 slot_index) 43862306a36Sopenharmony_ci{ 43962306a36Sopenharmony_ci int i; 44062306a36Sopenharmony_ci 44162306a36Sopenharmony_ci for (i = mlxsw_m->max_modules_per_slot - 1; i >= 0; i--) { 44262306a36Sopenharmony_ci int *module_to_port; 44362306a36Sopenharmony_ci 44462306a36Sopenharmony_ci module_to_port = mlxsw_m_port_mapping_get(mlxsw_m, slot_index, i); 44562306a36Sopenharmony_ci if (*module_to_port > 0) 44662306a36Sopenharmony_ci mlxsw_m_port_module_unmap(mlxsw_m, slot_index, i); 44762306a36Sopenharmony_ci } 44862306a36Sopenharmony_ci} 44962306a36Sopenharmony_ci 45062306a36Sopenharmony_cistatic int 45162306a36Sopenharmony_cimlxsw_m_linecard_ports_create(struct mlxsw_m *mlxsw_m, u8 slot_index) 45262306a36Sopenharmony_ci{ 45362306a36Sopenharmony_ci int *module_to_port; 45462306a36Sopenharmony_ci int i, err; 45562306a36Sopenharmony_ci 45662306a36Sopenharmony_ci for (i = 0; i < mlxsw_m->max_modules_per_slot; i++) { 45762306a36Sopenharmony_ci module_to_port = mlxsw_m_port_mapping_get(mlxsw_m, slot_index, i); 45862306a36Sopenharmony_ci if (*module_to_port > 0) { 45962306a36Sopenharmony_ci err = mlxsw_m_port_create(mlxsw_m, *module_to_port, 46062306a36Sopenharmony_ci slot_index, i); 46162306a36Sopenharmony_ci if (err) 46262306a36Sopenharmony_ci goto err_port_create; 46362306a36Sopenharmony_ci /* Mark slot as active */ 46462306a36Sopenharmony_ci if (!mlxsw_m->line_cards[slot_index]->active) 46562306a36Sopenharmony_ci mlxsw_m->line_cards[slot_index]->active = true; 46662306a36Sopenharmony_ci } 46762306a36Sopenharmony_ci } 46862306a36Sopenharmony_ci return 0; 46962306a36Sopenharmony_ci 47062306a36Sopenharmony_cierr_port_create: 47162306a36Sopenharmony_ci for (i--; i >= 0; i--) { 47262306a36Sopenharmony_ci module_to_port = mlxsw_m_port_mapping_get(mlxsw_m, slot_index, i); 47362306a36Sopenharmony_ci if (*module_to_port > 0 && 47462306a36Sopenharmony_ci mlxsw_m_port_created(mlxsw_m, *module_to_port)) { 47562306a36Sopenharmony_ci mlxsw_m_port_remove(mlxsw_m, *module_to_port); 47662306a36Sopenharmony_ci /* Mark slot as inactive */ 47762306a36Sopenharmony_ci if (mlxsw_m->line_cards[slot_index]->active) 47862306a36Sopenharmony_ci mlxsw_m->line_cards[slot_index]->active = false; 47962306a36Sopenharmony_ci } 48062306a36Sopenharmony_ci } 48162306a36Sopenharmony_ci return err; 48262306a36Sopenharmony_ci} 48362306a36Sopenharmony_ci 48462306a36Sopenharmony_cistatic void 48562306a36Sopenharmony_cimlxsw_m_linecard_ports_remove(struct mlxsw_m *mlxsw_m, u8 slot_index) 48662306a36Sopenharmony_ci{ 48762306a36Sopenharmony_ci int i; 48862306a36Sopenharmony_ci 48962306a36Sopenharmony_ci for (i = 0; i < mlxsw_m->max_modules_per_slot; i++) { 49062306a36Sopenharmony_ci int *module_to_port = mlxsw_m_port_mapping_get(mlxsw_m, 49162306a36Sopenharmony_ci slot_index, i); 49262306a36Sopenharmony_ci 49362306a36Sopenharmony_ci if (*module_to_port > 0 && 49462306a36Sopenharmony_ci mlxsw_m_port_created(mlxsw_m, *module_to_port)) { 49562306a36Sopenharmony_ci mlxsw_m_port_remove(mlxsw_m, *module_to_port); 49662306a36Sopenharmony_ci mlxsw_m_port_module_unmap(mlxsw_m, slot_index, i); 49762306a36Sopenharmony_ci } 49862306a36Sopenharmony_ci } 49962306a36Sopenharmony_ci} 50062306a36Sopenharmony_ci 50162306a36Sopenharmony_cistatic int mlxsw_m_ports_module_map(struct mlxsw_m *mlxsw_m) 50262306a36Sopenharmony_ci{ 50362306a36Sopenharmony_ci unsigned int max_ports = mlxsw_core_max_ports(mlxsw_m->core); 50462306a36Sopenharmony_ci u8 last_module = max_ports; 50562306a36Sopenharmony_ci int i, err; 50662306a36Sopenharmony_ci 50762306a36Sopenharmony_ci for (i = 1; i < max_ports; i++) { 50862306a36Sopenharmony_ci err = mlxsw_m_port_module_map(mlxsw_m, i, &last_module); 50962306a36Sopenharmony_ci if (err) 51062306a36Sopenharmony_ci return err; 51162306a36Sopenharmony_ci } 51262306a36Sopenharmony_ci 51362306a36Sopenharmony_ci return 0; 51462306a36Sopenharmony_ci} 51562306a36Sopenharmony_ci 51662306a36Sopenharmony_cistatic int mlxsw_m_ports_create(struct mlxsw_m *mlxsw_m) 51762306a36Sopenharmony_ci{ 51862306a36Sopenharmony_ci int err; 51962306a36Sopenharmony_ci 52062306a36Sopenharmony_ci /* Fill out module to local port mapping array */ 52162306a36Sopenharmony_ci err = mlxsw_m_ports_module_map(mlxsw_m); 52262306a36Sopenharmony_ci if (err) 52362306a36Sopenharmony_ci goto err_ports_module_map; 52462306a36Sopenharmony_ci 52562306a36Sopenharmony_ci /* Create port objects for each valid entry */ 52662306a36Sopenharmony_ci err = mlxsw_m_linecard_ports_create(mlxsw_m, 0); 52762306a36Sopenharmony_ci if (err) 52862306a36Sopenharmony_ci goto err_linecard_ports_create; 52962306a36Sopenharmony_ci 53062306a36Sopenharmony_ci return 0; 53162306a36Sopenharmony_ci 53262306a36Sopenharmony_cierr_linecard_ports_create: 53362306a36Sopenharmony_cierr_ports_module_map: 53462306a36Sopenharmony_ci mlxsw_m_linecard_port_module_unmap(mlxsw_m, 0); 53562306a36Sopenharmony_ci 53662306a36Sopenharmony_ci return err; 53762306a36Sopenharmony_ci} 53862306a36Sopenharmony_ci 53962306a36Sopenharmony_cistatic void mlxsw_m_ports_remove(struct mlxsw_m *mlxsw_m) 54062306a36Sopenharmony_ci{ 54162306a36Sopenharmony_ci mlxsw_m_linecard_ports_remove(mlxsw_m, 0); 54262306a36Sopenharmony_ci} 54362306a36Sopenharmony_ci 54462306a36Sopenharmony_cistatic void 54562306a36Sopenharmony_cimlxsw_m_ports_remove_selected(struct mlxsw_core *mlxsw_core, 54662306a36Sopenharmony_ci bool (*selector)(void *priv, u16 local_port), 54762306a36Sopenharmony_ci void *priv) 54862306a36Sopenharmony_ci{ 54962306a36Sopenharmony_ci struct mlxsw_m *mlxsw_m = mlxsw_core_driver_priv(mlxsw_core); 55062306a36Sopenharmony_ci struct mlxsw_linecard *linecard_priv = priv; 55162306a36Sopenharmony_ci struct mlxsw_m_line_card *linecard; 55262306a36Sopenharmony_ci 55362306a36Sopenharmony_ci linecard = mlxsw_m->line_cards[linecard_priv->slot_index]; 55462306a36Sopenharmony_ci 55562306a36Sopenharmony_ci if (WARN_ON(!linecard->active)) 55662306a36Sopenharmony_ci return; 55762306a36Sopenharmony_ci 55862306a36Sopenharmony_ci mlxsw_m_linecard_ports_remove(mlxsw_m, linecard_priv->slot_index); 55962306a36Sopenharmony_ci linecard->active = false; 56062306a36Sopenharmony_ci} 56162306a36Sopenharmony_ci 56262306a36Sopenharmony_cistatic int mlxsw_m_fw_rev_validate(struct mlxsw_m *mlxsw_m) 56362306a36Sopenharmony_ci{ 56462306a36Sopenharmony_ci const struct mlxsw_fw_rev *rev = &mlxsw_m->bus_info->fw_rev; 56562306a36Sopenharmony_ci 56662306a36Sopenharmony_ci /* Validate driver and FW are compatible. 56762306a36Sopenharmony_ci * Do not check major version, since it defines chip type, while 56862306a36Sopenharmony_ci * driver is supposed to support any type. 56962306a36Sopenharmony_ci */ 57062306a36Sopenharmony_ci if (mlxsw_core_fw_rev_minor_subminor_validate(rev, &mlxsw_m_fw_rev)) 57162306a36Sopenharmony_ci return 0; 57262306a36Sopenharmony_ci 57362306a36Sopenharmony_ci dev_err(mlxsw_m->bus_info->dev, "The firmware version %d.%d.%d is incompatible with the driver (required >= %d.%d.%d)\n", 57462306a36Sopenharmony_ci rev->major, rev->minor, rev->subminor, rev->major, 57562306a36Sopenharmony_ci mlxsw_m_fw_rev.minor, mlxsw_m_fw_rev.subminor); 57662306a36Sopenharmony_ci 57762306a36Sopenharmony_ci return -EINVAL; 57862306a36Sopenharmony_ci} 57962306a36Sopenharmony_ci 58062306a36Sopenharmony_cistatic void 58162306a36Sopenharmony_cimlxsw_m_got_active(struct mlxsw_core *mlxsw_core, u8 slot_index, void *priv) 58262306a36Sopenharmony_ci{ 58362306a36Sopenharmony_ci struct mlxsw_m_line_card *linecard; 58462306a36Sopenharmony_ci struct mlxsw_m *mlxsw_m = priv; 58562306a36Sopenharmony_ci int err; 58662306a36Sopenharmony_ci 58762306a36Sopenharmony_ci linecard = mlxsw_m->line_cards[slot_index]; 58862306a36Sopenharmony_ci /* Skip if line card has been already configured during init */ 58962306a36Sopenharmony_ci if (linecard->active) 59062306a36Sopenharmony_ci return; 59162306a36Sopenharmony_ci 59262306a36Sopenharmony_ci /* Fill out module to local port mapping array */ 59362306a36Sopenharmony_ci err = mlxsw_m_ports_module_map(mlxsw_m); 59462306a36Sopenharmony_ci if (err) 59562306a36Sopenharmony_ci goto err_ports_module_map; 59662306a36Sopenharmony_ci 59762306a36Sopenharmony_ci /* Create port objects for each valid entry */ 59862306a36Sopenharmony_ci err = mlxsw_m_linecard_ports_create(mlxsw_m, slot_index); 59962306a36Sopenharmony_ci if (err) { 60062306a36Sopenharmony_ci dev_err(mlxsw_m->bus_info->dev, "Failed to create port for line card at slot %d\n", 60162306a36Sopenharmony_ci slot_index); 60262306a36Sopenharmony_ci goto err_linecard_ports_create; 60362306a36Sopenharmony_ci } 60462306a36Sopenharmony_ci 60562306a36Sopenharmony_ci linecard->active = true; 60662306a36Sopenharmony_ci 60762306a36Sopenharmony_ci return; 60862306a36Sopenharmony_ci 60962306a36Sopenharmony_cierr_linecard_ports_create: 61062306a36Sopenharmony_cierr_ports_module_map: 61162306a36Sopenharmony_ci mlxsw_m_linecard_port_module_unmap(mlxsw_m, slot_index); 61262306a36Sopenharmony_ci} 61362306a36Sopenharmony_ci 61462306a36Sopenharmony_cistatic void 61562306a36Sopenharmony_cimlxsw_m_got_inactive(struct mlxsw_core *mlxsw_core, u8 slot_index, void *priv) 61662306a36Sopenharmony_ci{ 61762306a36Sopenharmony_ci struct mlxsw_m_line_card *linecard; 61862306a36Sopenharmony_ci struct mlxsw_m *mlxsw_m = priv; 61962306a36Sopenharmony_ci 62062306a36Sopenharmony_ci linecard = mlxsw_m->line_cards[slot_index]; 62162306a36Sopenharmony_ci 62262306a36Sopenharmony_ci if (WARN_ON(!linecard->active)) 62362306a36Sopenharmony_ci return; 62462306a36Sopenharmony_ci 62562306a36Sopenharmony_ci mlxsw_m_linecard_ports_remove(mlxsw_m, slot_index); 62662306a36Sopenharmony_ci linecard->active = false; 62762306a36Sopenharmony_ci} 62862306a36Sopenharmony_ci 62962306a36Sopenharmony_cistatic struct mlxsw_linecards_event_ops mlxsw_m_event_ops = { 63062306a36Sopenharmony_ci .got_active = mlxsw_m_got_active, 63162306a36Sopenharmony_ci .got_inactive = mlxsw_m_got_inactive, 63262306a36Sopenharmony_ci}; 63362306a36Sopenharmony_ci 63462306a36Sopenharmony_cistatic int mlxsw_m_init(struct mlxsw_core *mlxsw_core, 63562306a36Sopenharmony_ci const struct mlxsw_bus_info *mlxsw_bus_info, 63662306a36Sopenharmony_ci struct netlink_ext_ack *extack) 63762306a36Sopenharmony_ci{ 63862306a36Sopenharmony_ci struct mlxsw_m *mlxsw_m = mlxsw_core_driver_priv(mlxsw_core); 63962306a36Sopenharmony_ci int err; 64062306a36Sopenharmony_ci 64162306a36Sopenharmony_ci mlxsw_m->core = mlxsw_core; 64262306a36Sopenharmony_ci mlxsw_m->bus_info = mlxsw_bus_info; 64362306a36Sopenharmony_ci 64462306a36Sopenharmony_ci err = mlxsw_m_fw_rev_validate(mlxsw_m); 64562306a36Sopenharmony_ci if (err) 64662306a36Sopenharmony_ci return err; 64762306a36Sopenharmony_ci 64862306a36Sopenharmony_ci err = mlxsw_m_base_mac_get(mlxsw_m); 64962306a36Sopenharmony_ci if (err) { 65062306a36Sopenharmony_ci dev_err(mlxsw_m->bus_info->dev, "Failed to get base mac\n"); 65162306a36Sopenharmony_ci return err; 65262306a36Sopenharmony_ci } 65362306a36Sopenharmony_ci 65462306a36Sopenharmony_ci err = mlxsw_m_linecards_init(mlxsw_m); 65562306a36Sopenharmony_ci if (err) { 65662306a36Sopenharmony_ci dev_err(mlxsw_m->bus_info->dev, "Failed to create line cards\n"); 65762306a36Sopenharmony_ci return err; 65862306a36Sopenharmony_ci } 65962306a36Sopenharmony_ci 66062306a36Sopenharmony_ci err = mlxsw_linecards_event_ops_register(mlxsw_core, 66162306a36Sopenharmony_ci &mlxsw_m_event_ops, mlxsw_m); 66262306a36Sopenharmony_ci if (err) { 66362306a36Sopenharmony_ci dev_err(mlxsw_m->bus_info->dev, "Failed to register line cards operations\n"); 66462306a36Sopenharmony_ci goto linecards_event_ops_register; 66562306a36Sopenharmony_ci } 66662306a36Sopenharmony_ci 66762306a36Sopenharmony_ci err = mlxsw_m_ports_create(mlxsw_m); 66862306a36Sopenharmony_ci if (err) { 66962306a36Sopenharmony_ci dev_err(mlxsw_m->bus_info->dev, "Failed to create ports\n"); 67062306a36Sopenharmony_ci goto err_ports_create; 67162306a36Sopenharmony_ci } 67262306a36Sopenharmony_ci 67362306a36Sopenharmony_ci return 0; 67462306a36Sopenharmony_ci 67562306a36Sopenharmony_cierr_ports_create: 67662306a36Sopenharmony_ci mlxsw_linecards_event_ops_unregister(mlxsw_core, 67762306a36Sopenharmony_ci &mlxsw_m_event_ops, mlxsw_m); 67862306a36Sopenharmony_cilinecards_event_ops_register: 67962306a36Sopenharmony_ci mlxsw_m_linecards_fini(mlxsw_m); 68062306a36Sopenharmony_ci return err; 68162306a36Sopenharmony_ci} 68262306a36Sopenharmony_ci 68362306a36Sopenharmony_cistatic void mlxsw_m_fini(struct mlxsw_core *mlxsw_core) 68462306a36Sopenharmony_ci{ 68562306a36Sopenharmony_ci struct mlxsw_m *mlxsw_m = mlxsw_core_driver_priv(mlxsw_core); 68662306a36Sopenharmony_ci 68762306a36Sopenharmony_ci mlxsw_m_ports_remove(mlxsw_m); 68862306a36Sopenharmony_ci mlxsw_linecards_event_ops_unregister(mlxsw_core, 68962306a36Sopenharmony_ci &mlxsw_m_event_ops, mlxsw_m); 69062306a36Sopenharmony_ci mlxsw_m_linecards_fini(mlxsw_m); 69162306a36Sopenharmony_ci} 69262306a36Sopenharmony_ci 69362306a36Sopenharmony_cistatic const struct mlxsw_config_profile mlxsw_m_config_profile; 69462306a36Sopenharmony_ci 69562306a36Sopenharmony_cistatic struct mlxsw_driver mlxsw_m_driver = { 69662306a36Sopenharmony_ci .kind = mlxsw_m_driver_name, 69762306a36Sopenharmony_ci .priv_size = sizeof(struct mlxsw_m), 69862306a36Sopenharmony_ci .init = mlxsw_m_init, 69962306a36Sopenharmony_ci .fini = mlxsw_m_fini, 70062306a36Sopenharmony_ci .ports_remove_selected = mlxsw_m_ports_remove_selected, 70162306a36Sopenharmony_ci .profile = &mlxsw_m_config_profile, 70262306a36Sopenharmony_ci}; 70362306a36Sopenharmony_ci 70462306a36Sopenharmony_cistatic const struct i2c_device_id mlxsw_m_i2c_id[] = { 70562306a36Sopenharmony_ci { "mlxsw_minimal", 0}, 70662306a36Sopenharmony_ci { }, 70762306a36Sopenharmony_ci}; 70862306a36Sopenharmony_ci 70962306a36Sopenharmony_cistatic struct i2c_driver mlxsw_m_i2c_driver = { 71062306a36Sopenharmony_ci .driver.name = "mlxsw_minimal", 71162306a36Sopenharmony_ci .class = I2C_CLASS_HWMON, 71262306a36Sopenharmony_ci .id_table = mlxsw_m_i2c_id, 71362306a36Sopenharmony_ci}; 71462306a36Sopenharmony_ci 71562306a36Sopenharmony_cistatic int __init mlxsw_m_module_init(void) 71662306a36Sopenharmony_ci{ 71762306a36Sopenharmony_ci int err; 71862306a36Sopenharmony_ci 71962306a36Sopenharmony_ci err = mlxsw_core_driver_register(&mlxsw_m_driver); 72062306a36Sopenharmony_ci if (err) 72162306a36Sopenharmony_ci return err; 72262306a36Sopenharmony_ci 72362306a36Sopenharmony_ci err = mlxsw_i2c_driver_register(&mlxsw_m_i2c_driver); 72462306a36Sopenharmony_ci if (err) 72562306a36Sopenharmony_ci goto err_i2c_driver_register; 72662306a36Sopenharmony_ci 72762306a36Sopenharmony_ci return 0; 72862306a36Sopenharmony_ci 72962306a36Sopenharmony_cierr_i2c_driver_register: 73062306a36Sopenharmony_ci mlxsw_core_driver_unregister(&mlxsw_m_driver); 73162306a36Sopenharmony_ci 73262306a36Sopenharmony_ci return err; 73362306a36Sopenharmony_ci} 73462306a36Sopenharmony_ci 73562306a36Sopenharmony_cistatic void __exit mlxsw_m_module_exit(void) 73662306a36Sopenharmony_ci{ 73762306a36Sopenharmony_ci mlxsw_i2c_driver_unregister(&mlxsw_m_i2c_driver); 73862306a36Sopenharmony_ci mlxsw_core_driver_unregister(&mlxsw_m_driver); 73962306a36Sopenharmony_ci} 74062306a36Sopenharmony_ci 74162306a36Sopenharmony_cimodule_init(mlxsw_m_module_init); 74262306a36Sopenharmony_cimodule_exit(mlxsw_m_module_exit); 74362306a36Sopenharmony_ci 74462306a36Sopenharmony_ciMODULE_LICENSE("Dual BSD/GPL"); 74562306a36Sopenharmony_ciMODULE_AUTHOR("Vadim Pasternak <vadimp@mellanox.com>"); 74662306a36Sopenharmony_ciMODULE_DESCRIPTION("Mellanox minimal driver"); 74762306a36Sopenharmony_ciMODULE_DEVICE_TABLE(i2c, mlxsw_m_i2c_id); 748