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 17 static const char mlxsw_m_driver_name[] = "mlxsw_minimal"; 18 19 struct mlxsw_m_port; 20 21 struct mlxsw_m { 22 struct mlxsw_m_port **ports; 23 int *module_to_port; 24 struct mlxsw_core *core; 25 const struct mlxsw_bus_info *bus_info; 26 u8 base_mac[ETH_ALEN]; 27 u8 max_ports; 28 }; 29 30 struct mlxsw_m_port { 31 struct net_device *dev; 32 struct mlxsw_m *mlxsw_m; 33 u8 local_port; 34 u8 module; 35 }; 36 37 static int mlxsw_m_base_mac_get(struct mlxsw_m *mlxsw_m) 38 { 39 char spad_pl[MLXSW_REG_SPAD_LEN] = {0}; 40 int err; 41 42 err = mlxsw_reg_query(mlxsw_m->core, MLXSW_REG(spad), spad_pl); 43 if (err) 44 return err; 45 mlxsw_reg_spad_base_mac_memcpy_from(spad_pl, mlxsw_m->base_mac); 46 return 0; 47 } 48 49 static int mlxsw_m_port_dummy_open_stop(struct net_device *dev) 50 { 51 return 0; 52 } 53 54 static struct devlink_port * 55 mlxsw_m_port_get_devlink_port(struct net_device *dev) 56 { 57 struct mlxsw_m_port *mlxsw_m_port = netdev_priv(dev); 58 struct mlxsw_m *mlxsw_m = mlxsw_m_port->mlxsw_m; 59 60 return mlxsw_core_port_devlink_port_get(mlxsw_m->core, 61 mlxsw_m_port->local_port); 62 } 63 64 static const struct net_device_ops mlxsw_m_port_netdev_ops = { 65 .ndo_open = mlxsw_m_port_dummy_open_stop, 66 .ndo_stop = mlxsw_m_port_dummy_open_stop, 67 .ndo_get_devlink_port = mlxsw_m_port_get_devlink_port, 68 }; 69 70 static void mlxsw_m_module_get_drvinfo(struct net_device *dev, 71 struct ethtool_drvinfo *drvinfo) 72 { 73 struct mlxsw_m_port *mlxsw_m_port = netdev_priv(dev); 74 struct mlxsw_m *mlxsw_m = mlxsw_m_port->mlxsw_m; 75 76 strlcpy(drvinfo->driver, mlxsw_m->bus_info->device_kind, 77 sizeof(drvinfo->driver)); 78 snprintf(drvinfo->fw_version, sizeof(drvinfo->fw_version), 79 "%d.%d.%d", 80 mlxsw_m->bus_info->fw_rev.major, 81 mlxsw_m->bus_info->fw_rev.minor, 82 mlxsw_m->bus_info->fw_rev.subminor); 83 strlcpy(drvinfo->bus_info, mlxsw_m->bus_info->device_name, 84 sizeof(drvinfo->bus_info)); 85 } 86 87 static int mlxsw_m_get_module_info(struct net_device *netdev, 88 struct ethtool_modinfo *modinfo) 89 { 90 struct mlxsw_m_port *mlxsw_m_port = netdev_priv(netdev); 91 struct mlxsw_core *core = mlxsw_m_port->mlxsw_m->core; 92 93 return mlxsw_env_get_module_info(core, mlxsw_m_port->module, modinfo); 94 } 95 96 static int 97 mlxsw_m_get_module_eeprom(struct net_device *netdev, struct ethtool_eeprom *ee, 98 u8 *data) 99 { 100 struct mlxsw_m_port *mlxsw_m_port = netdev_priv(netdev); 101 struct mlxsw_core *core = mlxsw_m_port->mlxsw_m->core; 102 103 return mlxsw_env_get_module_eeprom(netdev, core, mlxsw_m_port->module, 104 ee, data); 105 } 106 107 static const struct ethtool_ops mlxsw_m_port_ethtool_ops = { 108 .get_drvinfo = mlxsw_m_module_get_drvinfo, 109 .get_module_info = mlxsw_m_get_module_info, 110 .get_module_eeprom = mlxsw_m_get_module_eeprom, 111 }; 112 113 static int 114 mlxsw_m_port_module_info_get(struct mlxsw_m *mlxsw_m, u8 local_port, 115 u8 *p_module, u8 *p_width) 116 { 117 char pmlp_pl[MLXSW_REG_PMLP_LEN]; 118 int err; 119 120 mlxsw_reg_pmlp_pack(pmlp_pl, local_port); 121 err = mlxsw_reg_query(mlxsw_m->core, MLXSW_REG(pmlp), pmlp_pl); 122 if (err) 123 return err; 124 *p_module = mlxsw_reg_pmlp_module_get(pmlp_pl, 0); 125 *p_width = mlxsw_reg_pmlp_width_get(pmlp_pl); 126 127 return 0; 128 } 129 130 static int 131 mlxsw_m_port_dev_addr_get(struct mlxsw_m_port *mlxsw_m_port) 132 { 133 struct mlxsw_m *mlxsw_m = mlxsw_m_port->mlxsw_m; 134 struct net_device *dev = mlxsw_m_port->dev; 135 char ppad_pl[MLXSW_REG_PPAD_LEN]; 136 int err; 137 138 mlxsw_reg_ppad_pack(ppad_pl, false, 0); 139 err = mlxsw_reg_query(mlxsw_m->core, MLXSW_REG(ppad), ppad_pl); 140 if (err) 141 return err; 142 mlxsw_reg_ppad_mac_memcpy_from(ppad_pl, dev->dev_addr); 143 /* The last byte value in base mac address is guaranteed 144 * to be such it does not overflow when adding local_port 145 * value. 146 */ 147 dev->dev_addr[ETH_ALEN - 1] += mlxsw_m_port->module + 1; 148 return 0; 149 } 150 151 static int 152 mlxsw_m_port_create(struct mlxsw_m *mlxsw_m, u8 local_port, u8 module) 153 { 154 struct mlxsw_m_port *mlxsw_m_port; 155 struct net_device *dev; 156 int err; 157 158 err = mlxsw_core_port_init(mlxsw_m->core, local_port, 159 module + 1, false, 0, 160 mlxsw_m->base_mac, 161 sizeof(mlxsw_m->base_mac)); 162 if (err) { 163 dev_err(mlxsw_m->bus_info->dev, "Port %d: Failed to init core port\n", 164 local_port); 165 return err; 166 } 167 168 dev = alloc_etherdev(sizeof(struct mlxsw_m_port)); 169 if (!dev) { 170 err = -ENOMEM; 171 goto err_alloc_etherdev; 172 } 173 174 SET_NETDEV_DEV(dev, mlxsw_m->bus_info->dev); 175 mlxsw_m_port = netdev_priv(dev); 176 mlxsw_m_port->dev = dev; 177 mlxsw_m_port->mlxsw_m = mlxsw_m; 178 mlxsw_m_port->local_port = local_port; 179 mlxsw_m_port->module = module; 180 181 dev->netdev_ops = &mlxsw_m_port_netdev_ops; 182 dev->ethtool_ops = &mlxsw_m_port_ethtool_ops; 183 184 err = mlxsw_m_port_dev_addr_get(mlxsw_m_port); 185 if (err) { 186 dev_err(mlxsw_m->bus_info->dev, "Port %d: Unable to get port mac address\n", 187 mlxsw_m_port->local_port); 188 goto err_dev_addr_get; 189 } 190 191 netif_carrier_off(dev); 192 mlxsw_m->ports[local_port] = mlxsw_m_port; 193 err = register_netdev(dev); 194 if (err) { 195 dev_err(mlxsw_m->bus_info->dev, "Port %d: Failed to register netdev\n", 196 mlxsw_m_port->local_port); 197 goto err_register_netdev; 198 } 199 200 mlxsw_core_port_eth_set(mlxsw_m->core, mlxsw_m_port->local_port, 201 mlxsw_m_port, dev); 202 203 return 0; 204 205 err_register_netdev: 206 mlxsw_m->ports[local_port] = NULL; 207 free_netdev(dev); 208 err_dev_addr_get: 209 err_alloc_etherdev: 210 mlxsw_core_port_fini(mlxsw_m->core, local_port); 211 return err; 212 } 213 214 static void mlxsw_m_port_remove(struct mlxsw_m *mlxsw_m, u8 local_port) 215 { 216 struct mlxsw_m_port *mlxsw_m_port = mlxsw_m->ports[local_port]; 217 218 mlxsw_core_port_clear(mlxsw_m->core, local_port, mlxsw_m); 219 unregister_netdev(mlxsw_m_port->dev); /* This calls ndo_stop */ 220 mlxsw_m->ports[local_port] = NULL; 221 free_netdev(mlxsw_m_port->dev); 222 mlxsw_core_port_fini(mlxsw_m->core, local_port); 223 } 224 225 static int mlxsw_m_port_module_map(struct mlxsw_m *mlxsw_m, u8 local_port, 226 u8 *last_module) 227 { 228 u8 module, width; 229 int err; 230 231 /* Fill out to local port mapping array */ 232 err = mlxsw_m_port_module_info_get(mlxsw_m, local_port, &module, 233 &width); 234 if (err) 235 return err; 236 237 if (!width) 238 return 0; 239 /* Skip, if port belongs to the cluster */ 240 if (module == *last_module) 241 return 0; 242 *last_module = module; 243 mlxsw_m->module_to_port[module] = ++mlxsw_m->max_ports; 244 245 return 0; 246 } 247 248 static void mlxsw_m_port_module_unmap(struct mlxsw_m *mlxsw_m, u8 module) 249 { 250 mlxsw_m->module_to_port[module] = -1; 251 } 252 253 static int mlxsw_m_ports_create(struct mlxsw_m *mlxsw_m) 254 { 255 unsigned int max_ports = mlxsw_core_max_ports(mlxsw_m->core); 256 u8 last_module = max_ports; 257 int i; 258 int err; 259 260 mlxsw_m->ports = kcalloc(max_ports, sizeof(*mlxsw_m->ports), 261 GFP_KERNEL); 262 if (!mlxsw_m->ports) 263 return -ENOMEM; 264 265 mlxsw_m->module_to_port = kmalloc_array(max_ports, sizeof(int), 266 GFP_KERNEL); 267 if (!mlxsw_m->module_to_port) { 268 err = -ENOMEM; 269 goto err_module_to_port_alloc; 270 } 271 272 /* Invalidate the entries of module to local port mapping array */ 273 for (i = 0; i < max_ports; i++) 274 mlxsw_m->module_to_port[i] = -1; 275 276 /* Fill out module to local port mapping array */ 277 for (i = 1; i < max_ports; i++) { 278 err = mlxsw_m_port_module_map(mlxsw_m, i, &last_module); 279 if (err) 280 goto err_module_to_port_map; 281 } 282 283 /* Create port objects for each valid entry */ 284 for (i = 0; i < mlxsw_m->max_ports; i++) { 285 if (mlxsw_m->module_to_port[i] > 0) { 286 err = mlxsw_m_port_create(mlxsw_m, 287 mlxsw_m->module_to_port[i], 288 i); 289 if (err) 290 goto err_module_to_port_create; 291 } 292 } 293 294 return 0; 295 296 err_module_to_port_create: 297 for (i--; i >= 0; i--) { 298 if (mlxsw_m->module_to_port[i] > 0) 299 mlxsw_m_port_remove(mlxsw_m, 300 mlxsw_m->module_to_port[i]); 301 } 302 i = max_ports; 303 err_module_to_port_map: 304 for (i--; i > 0; i--) 305 mlxsw_m_port_module_unmap(mlxsw_m, i); 306 kfree(mlxsw_m->module_to_port); 307 err_module_to_port_alloc: 308 kfree(mlxsw_m->ports); 309 return err; 310 } 311 312 static void mlxsw_m_ports_remove(struct mlxsw_m *mlxsw_m) 313 { 314 int i; 315 316 for (i = 0; i < mlxsw_m->max_ports; i++) { 317 if (mlxsw_m->module_to_port[i] > 0) { 318 mlxsw_m_port_remove(mlxsw_m, 319 mlxsw_m->module_to_port[i]); 320 mlxsw_m_port_module_unmap(mlxsw_m, i); 321 } 322 } 323 324 kfree(mlxsw_m->module_to_port); 325 kfree(mlxsw_m->ports); 326 } 327 328 static int mlxsw_m_init(struct mlxsw_core *mlxsw_core, 329 const struct mlxsw_bus_info *mlxsw_bus_info) 330 { 331 struct mlxsw_m *mlxsw_m = mlxsw_core_driver_priv(mlxsw_core); 332 int err; 333 334 mlxsw_m->core = mlxsw_core; 335 mlxsw_m->bus_info = mlxsw_bus_info; 336 337 err = mlxsw_m_base_mac_get(mlxsw_m); 338 if (err) { 339 dev_err(mlxsw_m->bus_info->dev, "Failed to get base mac\n"); 340 return err; 341 } 342 343 err = mlxsw_m_ports_create(mlxsw_m); 344 if (err) { 345 dev_err(mlxsw_m->bus_info->dev, "Failed to create ports\n"); 346 return err; 347 } 348 349 return 0; 350 } 351 352 static void mlxsw_m_fini(struct mlxsw_core *mlxsw_core) 353 { 354 struct mlxsw_m *mlxsw_m = mlxsw_core_driver_priv(mlxsw_core); 355 356 mlxsw_m_ports_remove(mlxsw_m); 357 } 358 359 static const struct mlxsw_config_profile mlxsw_m_config_profile; 360 361 static struct mlxsw_driver mlxsw_m_driver = { 362 .kind = mlxsw_m_driver_name, 363 .priv_size = sizeof(struct mlxsw_m), 364 .init = mlxsw_m_init, 365 .fini = mlxsw_m_fini, 366 .profile = &mlxsw_m_config_profile, 367 .res_query_enabled = true, 368 }; 369 370 static const struct i2c_device_id mlxsw_m_i2c_id[] = { 371 { "mlxsw_minimal", 0}, 372 { }, 373 }; 374 375 static struct i2c_driver mlxsw_m_i2c_driver = { 376 .driver.name = "mlxsw_minimal", 377 .class = I2C_CLASS_HWMON, 378 .id_table = mlxsw_m_i2c_id, 379 }; 380 381 static int __init mlxsw_m_module_init(void) 382 { 383 int err; 384 385 err = mlxsw_core_driver_register(&mlxsw_m_driver); 386 if (err) 387 return err; 388 389 err = mlxsw_i2c_driver_register(&mlxsw_m_i2c_driver); 390 if (err) 391 goto err_i2c_driver_register; 392 393 return 0; 394 395 err_i2c_driver_register: 396 mlxsw_core_driver_unregister(&mlxsw_m_driver); 397 398 return err; 399 } 400 401 static void __exit mlxsw_m_module_exit(void) 402 { 403 mlxsw_i2c_driver_unregister(&mlxsw_m_i2c_driver); 404 mlxsw_core_driver_unregister(&mlxsw_m_driver); 405 } 406 407 module_init(mlxsw_m_module_init); 408 module_exit(mlxsw_m_module_exit); 409 410 MODULE_LICENSE("Dual BSD/GPL"); 411 MODULE_AUTHOR("Vadim Pasternak <vadimp@mellanox.com>"); 412 MODULE_DESCRIPTION("Mellanox minimal driver"); 413 MODULE_DEVICE_TABLE(i2c, mlxsw_m_i2c_id); 414