1 // SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0
2 /* Copyright (c) 2016-2019 Mellanox Technologies. All rights reserved */
4 #include <linux/netdevice.h>
5 #include <linux/etherdevice.h>
6 #include <linux/ethtool.h>
8 #include <linux/kernel.h>
9 #include <linux/module.h>
10 #include <linux/mod_devicetable.h>
11 #include <linux/types.h>
17 static const char mlxsw_m_driver_name
[] = "mlxsw_minimal";
22 struct mlxsw_m_port
**ports
;
24 struct mlxsw_core
*core
;
25 const struct mlxsw_bus_info
*bus_info
;
26 u8 base_mac
[ETH_ALEN
];
31 struct net_device
*dev
;
32 struct mlxsw_m
*mlxsw_m
;
37 static int mlxsw_m_base_mac_get(struct mlxsw_m
*mlxsw_m
)
39 char spad_pl
[MLXSW_REG_SPAD_LEN
] = {0};
42 err
= mlxsw_reg_query(mlxsw_m
->core
, MLXSW_REG(spad
), spad_pl
);
45 mlxsw_reg_spad_base_mac_memcpy_from(spad_pl
, mlxsw_m
->base_mac
);
49 static int mlxsw_m_port_dummy_open_stop(struct net_device
*dev
)
54 static struct devlink_port
*
55 mlxsw_m_port_get_devlink_port(struct net_device
*dev
)
57 struct mlxsw_m_port
*mlxsw_m_port
= netdev_priv(dev
);
58 struct mlxsw_m
*mlxsw_m
= mlxsw_m_port
->mlxsw_m
;
60 return mlxsw_core_port_devlink_port_get(mlxsw_m
->core
,
61 mlxsw_m_port
->local_port
);
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
,
70 static void mlxsw_m_module_get_drvinfo(struct net_device
*dev
,
71 struct ethtool_drvinfo
*drvinfo
)
73 struct mlxsw_m_port
*mlxsw_m_port
= netdev_priv(dev
);
74 struct mlxsw_m
*mlxsw_m
= mlxsw_m_port
->mlxsw_m
;
76 strlcpy(drvinfo
->driver
, mlxsw_m
->bus_info
->device_kind
,
77 sizeof(drvinfo
->driver
));
78 snprintf(drvinfo
->fw_version
, sizeof(drvinfo
->fw_version
),
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
));
87 static int mlxsw_m_get_module_info(struct net_device
*netdev
,
88 struct ethtool_modinfo
*modinfo
)
90 struct mlxsw_m_port
*mlxsw_m_port
= netdev_priv(netdev
);
91 struct mlxsw_core
*core
= mlxsw_m_port
->mlxsw_m
->core
;
93 return mlxsw_env_get_module_info(core
, mlxsw_m_port
->module
, modinfo
);
97 mlxsw_m_get_module_eeprom(struct net_device
*netdev
, struct ethtool_eeprom
*ee
,
100 struct mlxsw_m_port
*mlxsw_m_port
= netdev_priv(netdev
);
101 struct mlxsw_core
*core
= mlxsw_m_port
->mlxsw_m
->core
;
103 return mlxsw_env_get_module_eeprom(netdev
, core
, mlxsw_m_port
->module
,
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
,
114 mlxsw_m_port_module_info_get(struct mlxsw_m
*mlxsw_m
, u8 local_port
,
115 u8
*p_module
, u8
*p_width
)
117 char pmlp_pl
[MLXSW_REG_PMLP_LEN
];
120 mlxsw_reg_pmlp_pack(pmlp_pl
, local_port
);
121 err
= mlxsw_reg_query(mlxsw_m
->core
, MLXSW_REG(pmlp
), pmlp_pl
);
124 *p_module
= mlxsw_reg_pmlp_module_get(pmlp_pl
, 0);
125 *p_width
= mlxsw_reg_pmlp_width_get(pmlp_pl
);
131 mlxsw_m_port_dev_addr_get(struct mlxsw_m_port
*mlxsw_m_port
)
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
];
138 mlxsw_reg_ppad_pack(ppad_pl
, false, 0);
139 err
= mlxsw_reg_query(mlxsw_m
->core
, MLXSW_REG(ppad
), ppad_pl
);
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
147 dev
->dev_addr
[ETH_ALEN
- 1] += mlxsw_m_port
->module
+ 1;
152 mlxsw_m_port_create(struct mlxsw_m
*mlxsw_m
, u8 local_port
, u8 module
)
154 struct mlxsw_m_port
*mlxsw_m_port
;
155 struct net_device
*dev
;
158 err
= mlxsw_core_port_init(mlxsw_m
->core
, local_port
,
159 module
+ 1, false, 0,
161 sizeof(mlxsw_m
->base_mac
));
163 dev_err(mlxsw_m
->bus_info
->dev
, "Port %d: Failed to init core port\n",
168 dev
= alloc_etherdev(sizeof(struct mlxsw_m_port
));
171 goto err_alloc_etherdev
;
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
;
181 dev
->netdev_ops
= &mlxsw_m_port_netdev_ops
;
182 dev
->ethtool_ops
= &mlxsw_m_port_ethtool_ops
;
184 err
= mlxsw_m_port_dev_addr_get(mlxsw_m_port
);
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
;
191 netif_carrier_off(dev
);
192 mlxsw_m
->ports
[local_port
] = mlxsw_m_port
;
193 err
= register_netdev(dev
);
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
;
200 mlxsw_core_port_eth_set(mlxsw_m
->core
, mlxsw_m_port
->local_port
,
206 mlxsw_m
->ports
[local_port
] = NULL
;
210 mlxsw_core_port_fini(mlxsw_m
->core
, local_port
);
214 static void mlxsw_m_port_remove(struct mlxsw_m
*mlxsw_m
, u8 local_port
)
216 struct mlxsw_m_port
*mlxsw_m_port
= mlxsw_m
->ports
[local_port
];
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
);
225 static int mlxsw_m_port_module_map(struct mlxsw_m
*mlxsw_m
, u8 local_port
,
231 /* Fill out to local port mapping array */
232 err
= mlxsw_m_port_module_info_get(mlxsw_m
, local_port
, &module
,
239 /* Skip, if port belongs to the cluster */
240 if (module
== *last_module
)
242 *last_module
= module
;
243 mlxsw_m
->module_to_port
[module
] = ++mlxsw_m
->max_ports
;
248 static void mlxsw_m_port_module_unmap(struct mlxsw_m
*mlxsw_m
, u8 module
)
250 mlxsw_m
->module_to_port
[module
] = -1;
253 static int mlxsw_m_ports_create(struct mlxsw_m
*mlxsw_m
)
255 unsigned int max_ports
= mlxsw_core_max_ports(mlxsw_m
->core
);
256 u8 last_module
= max_ports
;
260 mlxsw_m
->ports
= kcalloc(max_ports
, sizeof(*mlxsw_m
->ports
),
265 mlxsw_m
->module_to_port
= kmalloc_array(max_ports
, sizeof(int),
267 if (!mlxsw_m
->module_to_port
) {
269 goto err_module_to_port_alloc
;
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;
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
);
280 goto err_module_to_port_map
;
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
],
290 goto err_module_to_port_create
;
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
]);
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
);
312 static void mlxsw_m_ports_remove(struct mlxsw_m
*mlxsw_m
)
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
);
324 kfree(mlxsw_m
->module_to_port
);
325 kfree(mlxsw_m
->ports
);
328 static int mlxsw_m_init(struct mlxsw_core
*mlxsw_core
,
329 const struct mlxsw_bus_info
*mlxsw_bus_info
)
331 struct mlxsw_m
*mlxsw_m
= mlxsw_core_driver_priv(mlxsw_core
);
334 mlxsw_m
->core
= mlxsw_core
;
335 mlxsw_m
->bus_info
= mlxsw_bus_info
;
337 err
= mlxsw_m_base_mac_get(mlxsw_m
);
339 dev_err(mlxsw_m
->bus_info
->dev
, "Failed to get base mac\n");
343 err
= mlxsw_m_ports_create(mlxsw_m
);
345 dev_err(mlxsw_m
->bus_info
->dev
, "Failed to create ports\n");
352 static void mlxsw_m_fini(struct mlxsw_core
*mlxsw_core
)
354 struct mlxsw_m
*mlxsw_m
= mlxsw_core_driver_priv(mlxsw_core
);
356 mlxsw_m_ports_remove(mlxsw_m
);
359 static const struct mlxsw_config_profile mlxsw_m_config_profile
;
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,
370 static const struct i2c_device_id mlxsw_m_i2c_id
[] = {
371 { "mlxsw_minimal", 0},
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
,
381 static int __init
mlxsw_m_module_init(void)
385 err
= mlxsw_core_driver_register(&mlxsw_m_driver
);
389 err
= mlxsw_i2c_driver_register(&mlxsw_m_i2c_driver
);
391 goto err_i2c_driver_register
;
395 err_i2c_driver_register
:
396 mlxsw_core_driver_unregister(&mlxsw_m_driver
);
401 static void __exit
mlxsw_m_module_exit(void)
403 mlxsw_i2c_driver_unregister(&mlxsw_m_i2c_driver
);
404 mlxsw_core_driver_unregister(&mlxsw_m_driver
);
407 module_init(mlxsw_m_module_init
);
408 module_exit(mlxsw_m_module_exit
);
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
);