cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

minimal.c (13676B)


      1// SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0
      2/* Copyright (c) 2016-2019 Mellanox Technologies. All rights reserved */
      3
      4#include <linux/netdevice.h>
      5#include <linux/etherdevice.h>
      6#include <linux/ethtool.h>
      7#include <linux/i2c.h>
      8#include <linux/kernel.h>
      9#include <linux/module.h>
     10#include <linux/mod_devicetable.h>
     11#include <linux/types.h>
     12
     13#include "core.h"
     14#include "core_env.h"
     15#include "i2c.h"
     16
     17static const char mlxsw_m_driver_name[] = "mlxsw_minimal";
     18
     19#define MLXSW_M_FWREV_MINOR	2000
     20#define MLXSW_M_FWREV_SUBMINOR	1886
     21
     22static const struct mlxsw_fw_rev mlxsw_m_fw_rev = {
     23	.minor = MLXSW_M_FWREV_MINOR,
     24	.subminor = MLXSW_M_FWREV_SUBMINOR,
     25};
     26
     27struct mlxsw_m_port;
     28
     29struct mlxsw_m {
     30	struct mlxsw_m_port **ports;
     31	int *module_to_port;
     32	struct mlxsw_core *core;
     33	const struct mlxsw_bus_info *bus_info;
     34	u8 base_mac[ETH_ALEN];
     35	u8 max_ports;
     36};
     37
     38struct mlxsw_m_port {
     39	struct net_device *dev;
     40	struct mlxsw_m *mlxsw_m;
     41	u16 local_port;
     42	u8 module;
     43};
     44
     45static int mlxsw_m_base_mac_get(struct mlxsw_m *mlxsw_m)
     46{
     47	char spad_pl[MLXSW_REG_SPAD_LEN] = {0};
     48	int err;
     49
     50	err = mlxsw_reg_query(mlxsw_m->core, MLXSW_REG(spad), spad_pl);
     51	if (err)
     52		return err;
     53	mlxsw_reg_spad_base_mac_memcpy_from(spad_pl, mlxsw_m->base_mac);
     54	return 0;
     55}
     56
     57static int mlxsw_m_port_open(struct net_device *dev)
     58{
     59	struct mlxsw_m_port *mlxsw_m_port = netdev_priv(dev);
     60	struct mlxsw_m *mlxsw_m = mlxsw_m_port->mlxsw_m;
     61
     62	return mlxsw_env_module_port_up(mlxsw_m->core, 0,
     63					mlxsw_m_port->module);
     64}
     65
     66static int mlxsw_m_port_stop(struct net_device *dev)
     67{
     68	struct mlxsw_m_port *mlxsw_m_port = netdev_priv(dev);
     69	struct mlxsw_m *mlxsw_m = mlxsw_m_port->mlxsw_m;
     70
     71	mlxsw_env_module_port_down(mlxsw_m->core, 0, mlxsw_m_port->module);
     72	return 0;
     73}
     74
     75static struct devlink_port *
     76mlxsw_m_port_get_devlink_port(struct net_device *dev)
     77{
     78	struct mlxsw_m_port *mlxsw_m_port = netdev_priv(dev);
     79	struct mlxsw_m *mlxsw_m = mlxsw_m_port->mlxsw_m;
     80
     81	return mlxsw_core_port_devlink_port_get(mlxsw_m->core,
     82						mlxsw_m_port->local_port);
     83}
     84
     85static const struct net_device_ops mlxsw_m_port_netdev_ops = {
     86	.ndo_open		= mlxsw_m_port_open,
     87	.ndo_stop		= mlxsw_m_port_stop,
     88	.ndo_get_devlink_port	= mlxsw_m_port_get_devlink_port,
     89};
     90
     91static void mlxsw_m_module_get_drvinfo(struct net_device *dev,
     92				       struct ethtool_drvinfo *drvinfo)
     93{
     94	struct mlxsw_m_port *mlxsw_m_port = netdev_priv(dev);
     95	struct mlxsw_m *mlxsw_m = mlxsw_m_port->mlxsw_m;
     96
     97	strlcpy(drvinfo->driver, mlxsw_m->bus_info->device_kind,
     98		sizeof(drvinfo->driver));
     99	snprintf(drvinfo->fw_version, sizeof(drvinfo->fw_version),
    100		 "%d.%d.%d",
    101		 mlxsw_m->bus_info->fw_rev.major,
    102		 mlxsw_m->bus_info->fw_rev.minor,
    103		 mlxsw_m->bus_info->fw_rev.subminor);
    104	strlcpy(drvinfo->bus_info, mlxsw_m->bus_info->device_name,
    105		sizeof(drvinfo->bus_info));
    106}
    107
    108static int mlxsw_m_get_module_info(struct net_device *netdev,
    109				   struct ethtool_modinfo *modinfo)
    110{
    111	struct mlxsw_m_port *mlxsw_m_port = netdev_priv(netdev);
    112	struct mlxsw_core *core = mlxsw_m_port->mlxsw_m->core;
    113
    114	return mlxsw_env_get_module_info(netdev, core, 0, mlxsw_m_port->module,
    115					 modinfo);
    116}
    117
    118static int
    119mlxsw_m_get_module_eeprom(struct net_device *netdev, struct ethtool_eeprom *ee,
    120			  u8 *data)
    121{
    122	struct mlxsw_m_port *mlxsw_m_port = netdev_priv(netdev);
    123	struct mlxsw_core *core = mlxsw_m_port->mlxsw_m->core;
    124
    125	return mlxsw_env_get_module_eeprom(netdev, core, 0,
    126					   mlxsw_m_port->module, ee, data);
    127}
    128
    129static int
    130mlxsw_m_get_module_eeprom_by_page(struct net_device *netdev,
    131				  const struct ethtool_module_eeprom *page,
    132				  struct netlink_ext_ack *extack)
    133{
    134	struct mlxsw_m_port *mlxsw_m_port = netdev_priv(netdev);
    135	struct mlxsw_core *core = mlxsw_m_port->mlxsw_m->core;
    136
    137	return mlxsw_env_get_module_eeprom_by_page(core, 0,
    138						   mlxsw_m_port->module,
    139						   page, extack);
    140}
    141
    142static int mlxsw_m_reset(struct net_device *netdev, u32 *flags)
    143{
    144	struct mlxsw_m_port *mlxsw_m_port = netdev_priv(netdev);
    145	struct mlxsw_core *core = mlxsw_m_port->mlxsw_m->core;
    146
    147	return mlxsw_env_reset_module(netdev, core, 0, mlxsw_m_port->module,
    148				      flags);
    149}
    150
    151static int
    152mlxsw_m_get_module_power_mode(struct net_device *netdev,
    153			      struct ethtool_module_power_mode_params *params,
    154			      struct netlink_ext_ack *extack)
    155{
    156	struct mlxsw_m_port *mlxsw_m_port = netdev_priv(netdev);
    157	struct mlxsw_core *core = mlxsw_m_port->mlxsw_m->core;
    158
    159	return mlxsw_env_get_module_power_mode(core, 0, mlxsw_m_port->module,
    160					       params, extack);
    161}
    162
    163static int
    164mlxsw_m_set_module_power_mode(struct net_device *netdev,
    165			      const struct ethtool_module_power_mode_params *params,
    166			      struct netlink_ext_ack *extack)
    167{
    168	struct mlxsw_m_port *mlxsw_m_port = netdev_priv(netdev);
    169	struct mlxsw_core *core = mlxsw_m_port->mlxsw_m->core;
    170
    171	return mlxsw_env_set_module_power_mode(core, 0, mlxsw_m_port->module,
    172					       params->policy, extack);
    173}
    174
    175static const struct ethtool_ops mlxsw_m_port_ethtool_ops = {
    176	.get_drvinfo		= mlxsw_m_module_get_drvinfo,
    177	.get_module_info	= mlxsw_m_get_module_info,
    178	.get_module_eeprom	= mlxsw_m_get_module_eeprom,
    179	.get_module_eeprom_by_page = mlxsw_m_get_module_eeprom_by_page,
    180	.reset			= mlxsw_m_reset,
    181	.get_module_power_mode	= mlxsw_m_get_module_power_mode,
    182	.set_module_power_mode	= mlxsw_m_set_module_power_mode,
    183};
    184
    185static int
    186mlxsw_m_port_module_info_get(struct mlxsw_m *mlxsw_m, u16 local_port,
    187			     u8 *p_module, u8 *p_width)
    188{
    189	char pmlp_pl[MLXSW_REG_PMLP_LEN];
    190	int err;
    191
    192	mlxsw_reg_pmlp_pack(pmlp_pl, local_port);
    193	err = mlxsw_reg_query(mlxsw_m->core, MLXSW_REG(pmlp), pmlp_pl);
    194	if (err)
    195		return err;
    196	*p_module = mlxsw_reg_pmlp_module_get(pmlp_pl, 0);
    197	*p_width = mlxsw_reg_pmlp_width_get(pmlp_pl);
    198
    199	return 0;
    200}
    201
    202static int
    203mlxsw_m_port_dev_addr_get(struct mlxsw_m_port *mlxsw_m_port)
    204{
    205	struct mlxsw_m *mlxsw_m = mlxsw_m_port->mlxsw_m;
    206	char ppad_pl[MLXSW_REG_PPAD_LEN];
    207	u8 addr[ETH_ALEN];
    208	int err;
    209
    210	mlxsw_reg_ppad_pack(ppad_pl, false, 0);
    211	err = mlxsw_reg_query(mlxsw_m->core, MLXSW_REG(ppad), ppad_pl);
    212	if (err)
    213		return err;
    214	mlxsw_reg_ppad_mac_memcpy_from(ppad_pl, addr);
    215	eth_hw_addr_gen(mlxsw_m_port->dev, addr, mlxsw_m_port->module + 1);
    216	return 0;
    217}
    218
    219static int
    220mlxsw_m_port_create(struct mlxsw_m *mlxsw_m, u16 local_port, u8 module)
    221{
    222	struct mlxsw_m_port *mlxsw_m_port;
    223	struct net_device *dev;
    224	int err;
    225
    226	err = mlxsw_core_port_init(mlxsw_m->core, local_port, 0,
    227				   module + 1, false, 0, false,
    228				   0, mlxsw_m->base_mac,
    229				   sizeof(mlxsw_m->base_mac));
    230	if (err) {
    231		dev_err(mlxsw_m->bus_info->dev, "Port %d: Failed to init core port\n",
    232			local_port);
    233		return err;
    234	}
    235
    236	dev = alloc_etherdev(sizeof(struct mlxsw_m_port));
    237	if (!dev) {
    238		err = -ENOMEM;
    239		goto err_alloc_etherdev;
    240	}
    241
    242	SET_NETDEV_DEV(dev, mlxsw_m->bus_info->dev);
    243	dev_net_set(dev, mlxsw_core_net(mlxsw_m->core));
    244	mlxsw_m_port = netdev_priv(dev);
    245	mlxsw_m_port->dev = dev;
    246	mlxsw_m_port->mlxsw_m = mlxsw_m;
    247	mlxsw_m_port->local_port = local_port;
    248	mlxsw_m_port->module = module;
    249
    250	dev->netdev_ops = &mlxsw_m_port_netdev_ops;
    251	dev->ethtool_ops = &mlxsw_m_port_ethtool_ops;
    252
    253	err = mlxsw_m_port_dev_addr_get(mlxsw_m_port);
    254	if (err) {
    255		dev_err(mlxsw_m->bus_info->dev, "Port %d: Unable to get port mac address\n",
    256			mlxsw_m_port->local_port);
    257		goto err_dev_addr_get;
    258	}
    259
    260	netif_carrier_off(dev);
    261	mlxsw_m->ports[local_port] = mlxsw_m_port;
    262	err = register_netdev(dev);
    263	if (err) {
    264		dev_err(mlxsw_m->bus_info->dev, "Port %d: Failed to register netdev\n",
    265			mlxsw_m_port->local_port);
    266		goto err_register_netdev;
    267	}
    268
    269	mlxsw_core_port_eth_set(mlxsw_m->core, mlxsw_m_port->local_port,
    270				mlxsw_m_port, dev);
    271
    272	return 0;
    273
    274err_register_netdev:
    275	mlxsw_m->ports[local_port] = NULL;
    276err_dev_addr_get:
    277	free_netdev(dev);
    278err_alloc_etherdev:
    279	mlxsw_core_port_fini(mlxsw_m->core, local_port);
    280	return err;
    281}
    282
    283static void mlxsw_m_port_remove(struct mlxsw_m *mlxsw_m, u16 local_port)
    284{
    285	struct mlxsw_m_port *mlxsw_m_port = mlxsw_m->ports[local_port];
    286
    287	mlxsw_core_port_clear(mlxsw_m->core, local_port, mlxsw_m);
    288	unregister_netdev(mlxsw_m_port->dev); /* This calls ndo_stop */
    289	mlxsw_m->ports[local_port] = NULL;
    290	free_netdev(mlxsw_m_port->dev);
    291	mlxsw_core_port_fini(mlxsw_m->core, local_port);
    292}
    293
    294static int mlxsw_m_port_module_map(struct mlxsw_m *mlxsw_m, u16 local_port,
    295				   u8 *last_module)
    296{
    297	unsigned int max_ports = mlxsw_core_max_ports(mlxsw_m->core);
    298	u8 module, width;
    299	int err;
    300
    301	/* Fill out to local port mapping array */
    302	err = mlxsw_m_port_module_info_get(mlxsw_m, local_port, &module,
    303					   &width);
    304	if (err)
    305		return err;
    306
    307	if (!width)
    308		return 0;
    309	/* Skip, if port belongs to the cluster */
    310	if (module == *last_module)
    311		return 0;
    312	*last_module = module;
    313
    314	if (WARN_ON_ONCE(module >= max_ports))
    315		return -EINVAL;
    316	mlxsw_env_module_port_map(mlxsw_m->core, 0, module);
    317	mlxsw_m->module_to_port[module] = ++mlxsw_m->max_ports;
    318
    319	return 0;
    320}
    321
    322static void mlxsw_m_port_module_unmap(struct mlxsw_m *mlxsw_m, u8 module)
    323{
    324	mlxsw_m->module_to_port[module] = -1;
    325	mlxsw_env_module_port_unmap(mlxsw_m->core, 0, module);
    326}
    327
    328static int mlxsw_m_ports_create(struct mlxsw_m *mlxsw_m)
    329{
    330	unsigned int max_ports = mlxsw_core_max_ports(mlxsw_m->core);
    331	struct devlink *devlink = priv_to_devlink(mlxsw_m->core);
    332	u8 last_module = max_ports;
    333	int i;
    334	int err;
    335
    336	mlxsw_m->ports = kcalloc(max_ports, sizeof(*mlxsw_m->ports),
    337				 GFP_KERNEL);
    338	if (!mlxsw_m->ports)
    339		return -ENOMEM;
    340
    341	mlxsw_m->module_to_port = kmalloc_array(max_ports, sizeof(int),
    342						GFP_KERNEL);
    343	if (!mlxsw_m->module_to_port) {
    344		err = -ENOMEM;
    345		goto err_module_to_port_alloc;
    346	}
    347
    348	/* Invalidate the entries of module to local port mapping array */
    349	for (i = 0; i < max_ports; i++)
    350		mlxsw_m->module_to_port[i] = -1;
    351
    352	/* Fill out module to local port mapping array */
    353	for (i = 1; i < max_ports; i++) {
    354		err = mlxsw_m_port_module_map(mlxsw_m, i, &last_module);
    355		if (err)
    356			goto err_module_to_port_map;
    357	}
    358
    359	/* Create port objects for each valid entry */
    360	devl_lock(devlink);
    361	for (i = 0; i < mlxsw_m->max_ports; i++) {
    362		if (mlxsw_m->module_to_port[i] > 0 &&
    363		    !mlxsw_core_port_is_xm(mlxsw_m->core, i)) {
    364			err = mlxsw_m_port_create(mlxsw_m,
    365						  mlxsw_m->module_to_port[i],
    366						  i);
    367			if (err)
    368				goto err_module_to_port_create;
    369		}
    370	}
    371	devl_unlock(devlink);
    372
    373	return 0;
    374
    375err_module_to_port_create:
    376	for (i--; i >= 0; i--) {
    377		if (mlxsw_m->module_to_port[i] > 0)
    378			mlxsw_m_port_remove(mlxsw_m,
    379					    mlxsw_m->module_to_port[i]);
    380	}
    381	devl_unlock(devlink);
    382	i = max_ports;
    383err_module_to_port_map:
    384	for (i--; i > 0; i--)
    385		mlxsw_m_port_module_unmap(mlxsw_m, i);
    386	kfree(mlxsw_m->module_to_port);
    387err_module_to_port_alloc:
    388	kfree(mlxsw_m->ports);
    389	return err;
    390}
    391
    392static void mlxsw_m_ports_remove(struct mlxsw_m *mlxsw_m)
    393{
    394	struct devlink *devlink = priv_to_devlink(mlxsw_m->core);
    395	int i;
    396
    397	devl_lock(devlink);
    398	for (i = 0; i < mlxsw_m->max_ports; i++) {
    399		if (mlxsw_m->module_to_port[i] > 0) {
    400			mlxsw_m_port_remove(mlxsw_m,
    401					    mlxsw_m->module_to_port[i]);
    402			mlxsw_m_port_module_unmap(mlxsw_m, i);
    403		}
    404	}
    405	devl_unlock(devlink);
    406
    407	kfree(mlxsw_m->module_to_port);
    408	kfree(mlxsw_m->ports);
    409}
    410
    411static int mlxsw_m_fw_rev_validate(struct mlxsw_m *mlxsw_m)
    412{
    413	const struct mlxsw_fw_rev *rev = &mlxsw_m->bus_info->fw_rev;
    414
    415	/* Validate driver and FW are compatible.
    416	 * Do not check major version, since it defines chip type, while
    417	 * driver is supposed to support any type.
    418	 */
    419	if (mlxsw_core_fw_rev_minor_subminor_validate(rev, &mlxsw_m_fw_rev))
    420		return 0;
    421
    422	dev_err(mlxsw_m->bus_info->dev, "The firmware version %d.%d.%d is incompatible with the driver (required >= %d.%d.%d)\n",
    423		rev->major, rev->minor, rev->subminor, rev->major,
    424		mlxsw_m_fw_rev.minor, mlxsw_m_fw_rev.subminor);
    425
    426	return -EINVAL;
    427}
    428
    429static int mlxsw_m_init(struct mlxsw_core *mlxsw_core,
    430			const struct mlxsw_bus_info *mlxsw_bus_info,
    431			struct netlink_ext_ack *extack)
    432{
    433	struct mlxsw_m *mlxsw_m = mlxsw_core_driver_priv(mlxsw_core);
    434	int err;
    435
    436	mlxsw_m->core = mlxsw_core;
    437	mlxsw_m->bus_info = mlxsw_bus_info;
    438
    439	err = mlxsw_m_fw_rev_validate(mlxsw_m);
    440	if (err)
    441		return err;
    442
    443	err = mlxsw_m_base_mac_get(mlxsw_m);
    444	if (err) {
    445		dev_err(mlxsw_m->bus_info->dev, "Failed to get base mac\n");
    446		return err;
    447	}
    448
    449	err = mlxsw_m_ports_create(mlxsw_m);
    450	if (err) {
    451		dev_err(mlxsw_m->bus_info->dev, "Failed to create ports\n");
    452		return err;
    453	}
    454
    455	return 0;
    456}
    457
    458static void mlxsw_m_fini(struct mlxsw_core *mlxsw_core)
    459{
    460	struct mlxsw_m *mlxsw_m = mlxsw_core_driver_priv(mlxsw_core);
    461
    462	mlxsw_m_ports_remove(mlxsw_m);
    463}
    464
    465static const struct mlxsw_config_profile mlxsw_m_config_profile;
    466
    467static struct mlxsw_driver mlxsw_m_driver = {
    468	.kind			= mlxsw_m_driver_name,
    469	.priv_size		= sizeof(struct mlxsw_m),
    470	.init			= mlxsw_m_init,
    471	.fini			= mlxsw_m_fini,
    472	.profile		= &mlxsw_m_config_profile,
    473};
    474
    475static const struct i2c_device_id mlxsw_m_i2c_id[] = {
    476	{ "mlxsw_minimal", 0},
    477	{ },
    478};
    479
    480static struct i2c_driver mlxsw_m_i2c_driver = {
    481	.driver.name = "mlxsw_minimal",
    482	.class = I2C_CLASS_HWMON,
    483	.id_table = mlxsw_m_i2c_id,
    484};
    485
    486static int __init mlxsw_m_module_init(void)
    487{
    488	int err;
    489
    490	err = mlxsw_core_driver_register(&mlxsw_m_driver);
    491	if (err)
    492		return err;
    493
    494	err = mlxsw_i2c_driver_register(&mlxsw_m_i2c_driver);
    495	if (err)
    496		goto err_i2c_driver_register;
    497
    498	return 0;
    499
    500err_i2c_driver_register:
    501	mlxsw_core_driver_unregister(&mlxsw_m_driver);
    502
    503	return err;
    504}
    505
    506static void __exit mlxsw_m_module_exit(void)
    507{
    508	mlxsw_i2c_driver_unregister(&mlxsw_m_i2c_driver);
    509	mlxsw_core_driver_unregister(&mlxsw_m_driver);
    510}
    511
    512module_init(mlxsw_m_module_init);
    513module_exit(mlxsw_m_module_exit);
    514
    515MODULE_LICENSE("Dual BSD/GPL");
    516MODULE_AUTHOR("Vadim Pasternak <vadimp@mellanox.com>");
    517MODULE_DESCRIPTION("Mellanox minimal driver");
    518MODULE_DEVICE_TABLE(i2c, mlxsw_m_i2c_id);