File Index
Files and directories
Sign in
FILE

minimal.c

File preview with syntax highlighting.

linux-6.19.14/drivers/net/ethernet/mellanox/mlxsw/minimal.c C
  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_line_card {
 30	bool active;
 31	int module_to_port[];
 32};
 33
 34struct mlxsw_m {
 35	struct mlxsw_m_port **ports;
 36	struct mlxsw_core *core;
 37	const struct mlxsw_bus_info *bus_info;
 38	u8 base_mac[ETH_ALEN];
 39	u8 max_ports;
 40	u8 max_modules_per_slot; /* Maximum number of modules per-slot. */
 41	u8 num_of_slots; /* Including the main board. */
 42	struct mlxsw_m_line_card **line_cards;
 43};
 44
 45struct mlxsw_m_port {
 46	struct net_device *dev;
 47	struct mlxsw_m *mlxsw_m;
 48	u16 local_port;
 49	u8 slot_index;
 50	u8 module;
 51	u8 module_offset;
 52};
 53
 54static int mlxsw_m_base_mac_get(struct mlxsw_m *mlxsw_m)
 55{
 56	char spad_pl[MLXSW_REG_SPAD_LEN] = {0};
 57	int err;
 58
 59	err = mlxsw_reg_query(mlxsw_m->core, MLXSW_REG(spad), spad_pl);
 60	if (err)
 61		return err;
 62	mlxsw_reg_spad_base_mac_memcpy_from(spad_pl, mlxsw_m->base_mac);
 63	return 0;
 64}
 65
 66static int mlxsw_m_port_open(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	return mlxsw_env_module_port_up(mlxsw_m->core, 0,
 72					mlxsw_m_port->module);
 73}
 74
 75static int mlxsw_m_port_stop(struct net_device *dev)
 76{
 77	struct mlxsw_m_port *mlxsw_m_port = netdev_priv(dev);
 78	struct mlxsw_m *mlxsw_m = mlxsw_m_port->mlxsw_m;
 79
 80	mlxsw_env_module_port_down(mlxsw_m->core, 0, mlxsw_m_port->module);
 81	return 0;
 82}
 83
 84static const struct net_device_ops mlxsw_m_port_netdev_ops = {
 85	.ndo_open		= mlxsw_m_port_open,
 86	.ndo_stop		= mlxsw_m_port_stop,
 87};
 88
 89static void mlxsw_m_module_get_drvinfo(struct net_device *dev,
 90				       struct ethtool_drvinfo *drvinfo)
 91{
 92	struct mlxsw_m_port *mlxsw_m_port = netdev_priv(dev);
 93	struct mlxsw_m *mlxsw_m = mlxsw_m_port->mlxsw_m;
 94
 95	strscpy(drvinfo->driver, mlxsw_m->bus_info->device_kind,
 96		sizeof(drvinfo->driver));
 97	snprintf(drvinfo->fw_version, sizeof(drvinfo->fw_version),
 98		 "%d.%d.%d",
 99		 mlxsw_m->bus_info->fw_rev.major,
100		 mlxsw_m->bus_info->fw_rev.minor,
101		 mlxsw_m->bus_info->fw_rev.subminor);
102	strscpy(drvinfo->bus_info, mlxsw_m->bus_info->device_name,
103		sizeof(drvinfo->bus_info));
104}
105
106static int mlxsw_m_get_module_info(struct net_device *netdev,
107				   struct ethtool_modinfo *modinfo)
108{
109	struct mlxsw_m_port *mlxsw_m_port = netdev_priv(netdev);
110	struct mlxsw_core *core = mlxsw_m_port->mlxsw_m->core;
111
112	return mlxsw_env_get_module_info(netdev, core,
113					 mlxsw_m_port->slot_index,
114					 mlxsw_m_port->module, modinfo);
115}
116
117static int
118mlxsw_m_get_module_eeprom(struct net_device *netdev, struct ethtool_eeprom *ee,
119			  u8 *data)
120{
121	struct mlxsw_m_port *mlxsw_m_port = netdev_priv(netdev);
122	struct mlxsw_core *core = mlxsw_m_port->mlxsw_m->core;
123
124	return mlxsw_env_get_module_eeprom(netdev, core,
125					   mlxsw_m_port->slot_index,
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,
138						   mlxsw_m_port->slot_index,
139						   mlxsw_m_port->module,
140						   page, extack);
141}
142
143static int
144mlxsw_m_set_module_eeprom_by_page(struct net_device *netdev,
145				  const struct ethtool_module_eeprom *page,
146				  struct netlink_ext_ack *extack)
147{
148	struct mlxsw_m_port *mlxsw_m_port = netdev_priv(netdev);
149	struct mlxsw_core *core = mlxsw_m_port->mlxsw_m->core;
150
151	return mlxsw_env_set_module_eeprom_by_page(core,
152						   mlxsw_m_port->slot_index,
153						   mlxsw_m_port->module,
154						   page, extack);
155}
156
157static int mlxsw_m_reset(struct net_device *netdev, u32 *flags)
158{
159	struct mlxsw_m_port *mlxsw_m_port = netdev_priv(netdev);
160	struct mlxsw_core *core = mlxsw_m_port->mlxsw_m->core;
161
162	return mlxsw_env_reset_module(netdev, core, mlxsw_m_port->slot_index,
163				      mlxsw_m_port->module,
164				      flags);
165}
166
167static int
168mlxsw_m_get_module_power_mode(struct net_device *netdev,
169			      struct ethtool_module_power_mode_params *params,
170			      struct netlink_ext_ack *extack)
171{
172	struct mlxsw_m_port *mlxsw_m_port = netdev_priv(netdev);
173	struct mlxsw_core *core = mlxsw_m_port->mlxsw_m->core;
174
175	return mlxsw_env_get_module_power_mode(core, mlxsw_m_port->slot_index,
176					       mlxsw_m_port->module,
177					       params, extack);
178}
179
180static int
181mlxsw_m_set_module_power_mode(struct net_device *netdev,
182			      const struct ethtool_module_power_mode_params *params,
183			      struct netlink_ext_ack *extack)
184{
185	struct mlxsw_m_port *mlxsw_m_port = netdev_priv(netdev);
186	struct mlxsw_core *core = mlxsw_m_port->mlxsw_m->core;
187
188	return mlxsw_env_set_module_power_mode(core, mlxsw_m_port->slot_index,
189					       mlxsw_m_port->module,
190					       params->policy, extack);
191}
192
193static const struct ethtool_ops mlxsw_m_port_ethtool_ops = {
194	.get_drvinfo		= mlxsw_m_module_get_drvinfo,
195	.get_module_info	= mlxsw_m_get_module_info,
196	.get_module_eeprom	= mlxsw_m_get_module_eeprom,
197	.get_module_eeprom_by_page = mlxsw_m_get_module_eeprom_by_page,
198	.set_module_eeprom_by_page = mlxsw_m_set_module_eeprom_by_page,
199	.reset			= mlxsw_m_reset,
200	.get_module_power_mode	= mlxsw_m_get_module_power_mode,
201	.set_module_power_mode	= mlxsw_m_set_module_power_mode,
202};
203
204static int
205mlxsw_m_port_module_info_get(struct mlxsw_m *mlxsw_m, u16 local_port,
206			     u8 *p_module, u8 *p_width, u8 *p_slot_index)
207{
208	char pmlp_pl[MLXSW_REG_PMLP_LEN];
209	int err;
210
211	mlxsw_reg_pmlp_pack(pmlp_pl, local_port);
212	err = mlxsw_reg_query(mlxsw_m->core, MLXSW_REG(pmlp), pmlp_pl);
213	if (err)
214		return err;
215	*p_module = mlxsw_reg_pmlp_module_get(pmlp_pl, 0);
216	*p_width = mlxsw_reg_pmlp_width_get(pmlp_pl);
217	*p_slot_index = mlxsw_reg_pmlp_slot_index_get(pmlp_pl, 0);
218
219	return 0;
220}
221
222static int
223mlxsw_m_port_dev_addr_get(struct mlxsw_m_port *mlxsw_m_port)
224{
225	struct mlxsw_m *mlxsw_m = mlxsw_m_port->mlxsw_m;
226	char ppad_pl[MLXSW_REG_PPAD_LEN];
227	u8 addr[ETH_ALEN];
228	int err;
229
230	mlxsw_reg_ppad_pack(ppad_pl, false, 0);
231	err = mlxsw_reg_query(mlxsw_m->core, MLXSW_REG(ppad), ppad_pl);
232	if (err)
233		return err;
234	mlxsw_reg_ppad_mac_memcpy_from(ppad_pl, addr);
235	eth_hw_addr_gen(mlxsw_m_port->dev, addr, mlxsw_m_port->module + 1 +
236			mlxsw_m_port->module_offset);
237	return 0;
238}
239
240static bool mlxsw_m_port_created(struct mlxsw_m *mlxsw_m, u16 local_port)
241{
242	return mlxsw_m->ports[local_port];
243}
244
245static int
246mlxsw_m_port_create(struct mlxsw_m *mlxsw_m, u16 local_port, u8 slot_index,
247		    u8 module)
248{
249	struct mlxsw_m_port *mlxsw_m_port;
250	struct net_device *dev;
251	int err;
252
253	err = mlxsw_core_port_init(mlxsw_m->core, local_port, slot_index,
254				   module + 1, false, 0, false,
255				   0, mlxsw_m->base_mac,
256				   sizeof(mlxsw_m->base_mac));
257	if (err) {
258		dev_err(mlxsw_m->bus_info->dev, "Port %d: Failed to init core port\n",
259			local_port);
260		return err;
261	}
262
263	dev = alloc_etherdev(sizeof(struct mlxsw_m_port));
264	if (!dev) {
265		err = -ENOMEM;
266		goto err_alloc_etherdev;
267	}
268
269	SET_NETDEV_DEV(dev, mlxsw_m->bus_info->dev);
270	dev_net_set(dev, mlxsw_core_net(mlxsw_m->core));
271	mlxsw_m_port = netdev_priv(dev);
272	mlxsw_core_port_netdev_link(mlxsw_m->core, local_port,
273				    mlxsw_m_port, dev);
274	mlxsw_m_port->dev = dev;
275	mlxsw_m_port->mlxsw_m = mlxsw_m;
276	mlxsw_m_port->local_port = local_port;
277	mlxsw_m_port->module = module;
278	mlxsw_m_port->slot_index = slot_index;
279	/* Add module offset for line card. Offset for main board iz zero.
280	 * For line card in slot #n offset is calculated as (#n - 1)
281	 * multiplied by maximum modules number, which could be found on a line
282	 * card.
283	 */
284	mlxsw_m_port->module_offset = mlxsw_m_port->slot_index ?
285				      (mlxsw_m_port->slot_index - 1) *
286				      mlxsw_m->max_modules_per_slot : 0;
287
288	dev->netdev_ops = &mlxsw_m_port_netdev_ops;
289	dev->ethtool_ops = &mlxsw_m_port_ethtool_ops;
290
291	err = mlxsw_m_port_dev_addr_get(mlxsw_m_port);
292	if (err) {
293		dev_err(mlxsw_m->bus_info->dev, "Port %d: Unable to get port mac address\n",
294			mlxsw_m_port->local_port);
295		goto err_dev_addr_get;
296	}
297
298	netif_carrier_off(dev);
299	mlxsw_m->ports[local_port] = mlxsw_m_port;
300	err = register_netdev(dev);
301	if (err) {
302		dev_err(mlxsw_m->bus_info->dev, "Port %d: Failed to register netdev\n",
303			mlxsw_m_port->local_port);
304		goto err_register_netdev;
305	}
306
307	return 0;
308
309err_register_netdev:
310	mlxsw_m->ports[local_port] = NULL;
311err_dev_addr_get:
312	free_netdev(dev);
313err_alloc_etherdev:
314	mlxsw_core_port_fini(mlxsw_m->core, local_port);
315	return err;
316}
317
318static void mlxsw_m_port_remove(struct mlxsw_m *mlxsw_m, u16 local_port)
319{
320	struct mlxsw_m_port *mlxsw_m_port = mlxsw_m->ports[local_port];
321
322	unregister_netdev(mlxsw_m_port->dev); /* This calls ndo_stop */
323	mlxsw_m->ports[local_port] = NULL;
324	free_netdev(mlxsw_m_port->dev);
325	mlxsw_core_port_fini(mlxsw_m->core, local_port);
326}
327
328static int*
329mlxsw_m_port_mapping_get(struct mlxsw_m *mlxsw_m, u8 slot_index, u8 module)
330{
331	return &mlxsw_m->line_cards[slot_index]->module_to_port[module];
332}
333
334static int mlxsw_m_port_module_map(struct mlxsw_m *mlxsw_m, u16 local_port,
335				   u8 *last_module)
336{
337	unsigned int max_ports = mlxsw_core_max_ports(mlxsw_m->core);
338	u8 module, width, slot_index;
339	int *module_to_port;
340	int err;
341
342	/* Fill out to local port mapping array */
343	err = mlxsw_m_port_module_info_get(mlxsw_m, local_port, &module,
344					   &width, &slot_index);
345	if (err)
346		return err;
347
348	/* Skip if line card has been already configured */
349	if (mlxsw_m->line_cards[slot_index]->active)
350		return 0;
351	if (!width)
352		return 0;
353	/* Skip, if port belongs to the cluster */
354	if (module == *last_module)
355		return 0;
356	*last_module = module;
357
358	if (WARN_ON_ONCE(module >= max_ports))
359		return -EINVAL;
360	mlxsw_env_module_port_map(mlxsw_m->core, slot_index, module);
361	module_to_port = mlxsw_m_port_mapping_get(mlxsw_m, slot_index, module);
362	*module_to_port = local_port;
363
364	return 0;
365}
366
367static void
368mlxsw_m_port_module_unmap(struct mlxsw_m *mlxsw_m, u8 slot_index, u8 module)
369{
370	int *module_to_port = mlxsw_m_port_mapping_get(mlxsw_m, slot_index,
371						       module);
372	*module_to_port = -1;
373	mlxsw_env_module_port_unmap(mlxsw_m->core, slot_index, module);
374}
375
376static int mlxsw_m_linecards_init(struct mlxsw_m *mlxsw_m)
377{
378	unsigned int max_ports = mlxsw_core_max_ports(mlxsw_m->core);
379	char mgpir_pl[MLXSW_REG_MGPIR_LEN];
380	u8 num_of_modules;
381	int i, j, err;
382
383	mlxsw_reg_mgpir_pack(mgpir_pl, 0);
384	err = mlxsw_reg_query(mlxsw_m->core, MLXSW_REG(mgpir), mgpir_pl);
385	if (err)
386		return err;
387
388	mlxsw_reg_mgpir_unpack(mgpir_pl, NULL, NULL, NULL, &num_of_modules,
389			       &mlxsw_m->num_of_slots);
390	/* If the system is modular, get the maximum number of modules per-slot.
391	 * Otherwise, get the maximum number of modules on the main board.
392	 */
393	if (mlxsw_m->num_of_slots)
394		mlxsw_m->max_modules_per_slot =
395			mlxsw_reg_mgpir_max_modules_per_slot_get(mgpir_pl);
396	else
397		mlxsw_m->max_modules_per_slot = num_of_modules;
398	/* Add slot for main board. */
399	mlxsw_m->num_of_slots += 1;
400
401	mlxsw_m->ports = kcalloc(max_ports, sizeof(*mlxsw_m->ports),
402				 GFP_KERNEL);
403	if (!mlxsw_m->ports)
404		return -ENOMEM;
405
406	mlxsw_m->line_cards = kcalloc(mlxsw_m->num_of_slots,
407				      sizeof(*mlxsw_m->line_cards),
408				      GFP_KERNEL);
409	if (!mlxsw_m->line_cards) {
410		err = -ENOMEM;
411		goto err_kcalloc;
412	}
413
414	for (i = 0; i < mlxsw_m->num_of_slots; i++) {
415		mlxsw_m->line_cards[i] =
416			kzalloc(struct_size(mlxsw_m->line_cards[i],
417					    module_to_port,
418					    mlxsw_m->max_modules_per_slot),
419				GFP_KERNEL);
420		if (!mlxsw_m->line_cards[i]) {
421			err = -ENOMEM;
422			goto err_kmalloc_array;
423		}
424
425		/* Invalidate the entries of module to local port mapping array. */
426		for (j = 0; j < mlxsw_m->max_modules_per_slot; j++)
427			mlxsw_m->line_cards[i]->module_to_port[j] = -1;
428	}
429
430	return 0;
431
432err_kmalloc_array:
433	for (i--; i >= 0; i--)
434		kfree(mlxsw_m->line_cards[i]);
435	kfree(mlxsw_m->line_cards);
436err_kcalloc:
437	kfree(mlxsw_m->ports);
438	return err;
439}
440
441static void mlxsw_m_linecards_fini(struct mlxsw_m *mlxsw_m)
442{
443	int i = mlxsw_m->num_of_slots;
444
445	for (i--; i >= 0; i--)
446		kfree(mlxsw_m->line_cards[i]);
447	kfree(mlxsw_m->line_cards);
448	kfree(mlxsw_m->ports);
449}
450
451static void
452mlxsw_m_linecard_port_module_unmap(struct mlxsw_m *mlxsw_m, u8 slot_index)
453{
454	int i;
455
456	for (i = mlxsw_m->max_modules_per_slot - 1; i >= 0; i--) {
457		int *module_to_port;
458
459		module_to_port = mlxsw_m_port_mapping_get(mlxsw_m, slot_index, i);
460		if (*module_to_port > 0)
461			mlxsw_m_port_module_unmap(mlxsw_m, slot_index, i);
462	}
463}
464
465static int
466mlxsw_m_linecard_ports_create(struct mlxsw_m *mlxsw_m, u8 slot_index)
467{
468	int *module_to_port;
469	int i, err;
470
471	for (i = 0; i < mlxsw_m->max_modules_per_slot; i++) {
472		module_to_port = mlxsw_m_port_mapping_get(mlxsw_m, slot_index, i);
473		if (*module_to_port > 0) {
474			err = mlxsw_m_port_create(mlxsw_m, *module_to_port,
475						  slot_index, i);
476			if (err)
477				goto err_port_create;
478			/* Mark slot as active */
479			if (!mlxsw_m->line_cards[slot_index]->active)
480				mlxsw_m->line_cards[slot_index]->active = true;
481		}
482	}
483	return 0;
484
485err_port_create:
486	for (i--; i >= 0; i--) {
487		module_to_port = mlxsw_m_port_mapping_get(mlxsw_m, slot_index, i);
488		if (*module_to_port > 0 &&
489		    mlxsw_m_port_created(mlxsw_m, *module_to_port)) {
490			mlxsw_m_port_remove(mlxsw_m, *module_to_port);
491			/* Mark slot as inactive */
492			if (mlxsw_m->line_cards[slot_index]->active)
493				mlxsw_m->line_cards[slot_index]->active = false;
494		}
495	}
496	return err;
497}
498
499static void
500mlxsw_m_linecard_ports_remove(struct mlxsw_m *mlxsw_m, u8 slot_index)
501{
502	int i;
503
504	for (i = 0; i < mlxsw_m->max_modules_per_slot; i++) {
505		int *module_to_port = mlxsw_m_port_mapping_get(mlxsw_m,
506							       slot_index, i);
507
508		if (*module_to_port > 0 &&
509		    mlxsw_m_port_created(mlxsw_m, *module_to_port)) {
510			mlxsw_m_port_remove(mlxsw_m, *module_to_port);
511			mlxsw_m_port_module_unmap(mlxsw_m, slot_index, i);
512		}
513	}
514}
515
516static int mlxsw_m_ports_module_map(struct mlxsw_m *mlxsw_m)
517{
518	unsigned int max_ports = mlxsw_core_max_ports(mlxsw_m->core);
519	u8 last_module = max_ports;
520	int i, err;
521
522	for (i = 1; i < max_ports; i++) {
523		err = mlxsw_m_port_module_map(mlxsw_m, i, &last_module);
524		if (err)
525			return err;
526	}
527
528	return 0;
529}
530
531static int mlxsw_m_ports_create(struct mlxsw_m *mlxsw_m)
532{
533	int err;
534
535	/* Fill out module to local port mapping array */
536	err = mlxsw_m_ports_module_map(mlxsw_m);
537	if (err)
538		goto err_ports_module_map;
539
540	/* Create port objects for each valid entry */
541	err = mlxsw_m_linecard_ports_create(mlxsw_m, 0);
542	if (err)
543		goto err_linecard_ports_create;
544
545	return 0;
546
547err_linecard_ports_create:
548err_ports_module_map:
549	mlxsw_m_linecard_port_module_unmap(mlxsw_m, 0);
550
551	return err;
552}
553
554static void mlxsw_m_ports_remove(struct mlxsw_m *mlxsw_m)
555{
556	mlxsw_m_linecard_ports_remove(mlxsw_m, 0);
557}
558
559static void
560mlxsw_m_ports_remove_selected(struct mlxsw_core *mlxsw_core,
561			      bool (*selector)(void *priv, u16 local_port),
562			      void *priv)
563{
564	struct mlxsw_m *mlxsw_m = mlxsw_core_driver_priv(mlxsw_core);
565	struct mlxsw_linecard *linecard_priv = priv;
566	struct mlxsw_m_line_card *linecard;
567
568	linecard = mlxsw_m->line_cards[linecard_priv->slot_index];
569
570	if (WARN_ON(!linecard->active))
571		return;
572
573	mlxsw_m_linecard_ports_remove(mlxsw_m, linecard_priv->slot_index);
574	linecard->active = false;
575}
576
577static int mlxsw_m_fw_rev_validate(struct mlxsw_m *mlxsw_m)
578{
579	const struct mlxsw_fw_rev *rev = &mlxsw_m->bus_info->fw_rev;
580
581	/* Validate driver and FW are compatible.
582	 * Do not check major version, since it defines chip type, while
583	 * driver is supposed to support any type.
584	 */
585	if (mlxsw_core_fw_rev_minor_subminor_validate(rev, &mlxsw_m_fw_rev))
586		return 0;
587
588	dev_err(mlxsw_m->bus_info->dev, "The firmware version %d.%d.%d is incompatible with the driver (required >= %d.%d.%d)\n",
589		rev->major, rev->minor, rev->subminor, rev->major,
590		mlxsw_m_fw_rev.minor, mlxsw_m_fw_rev.subminor);
591
592	return -EINVAL;
593}
594
595static void
596mlxsw_m_got_active(struct mlxsw_core *mlxsw_core, u8 slot_index, void *priv)
597{
598	struct mlxsw_m_line_card *linecard;
599	struct mlxsw_m *mlxsw_m = priv;
600	int err;
601
602	linecard = mlxsw_m->line_cards[slot_index];
603	/* Skip if line card has been already configured during init */
604	if (linecard->active)
605		return;
606
607	/* Fill out module to local port mapping array */
608	err = mlxsw_m_ports_module_map(mlxsw_m);
609	if (err)
610		goto err_ports_module_map;
611
612	/* Create port objects for each valid entry */
613	err = mlxsw_m_linecard_ports_create(mlxsw_m, slot_index);
614	if (err) {
615		dev_err(mlxsw_m->bus_info->dev, "Failed to create port for line card at slot %d\n",
616			slot_index);
617		goto err_linecard_ports_create;
618	}
619
620	linecard->active = true;
621
622	return;
623
624err_linecard_ports_create:
625err_ports_module_map:
626	mlxsw_m_linecard_port_module_unmap(mlxsw_m, slot_index);
627}
628
629static void
630mlxsw_m_got_inactive(struct mlxsw_core *mlxsw_core, u8 slot_index, void *priv)
631{
632	struct mlxsw_m_line_card *linecard;
633	struct mlxsw_m *mlxsw_m = priv;
634
635	linecard = mlxsw_m->line_cards[slot_index];
636
637	if (WARN_ON(!linecard->active))
638		return;
639
640	mlxsw_m_linecard_ports_remove(mlxsw_m, slot_index);
641	linecard->active = false;
642}
643
644static struct mlxsw_linecards_event_ops mlxsw_m_event_ops = {
645	.got_active = mlxsw_m_got_active,
646	.got_inactive = mlxsw_m_got_inactive,
647};
648
649static int mlxsw_m_init(struct mlxsw_core *mlxsw_core,
650			const struct mlxsw_bus_info *mlxsw_bus_info,
651			struct netlink_ext_ack *extack)
652{
653	struct mlxsw_m *mlxsw_m = mlxsw_core_driver_priv(mlxsw_core);
654	int err;
655
656	mlxsw_m->core = mlxsw_core;
657	mlxsw_m->bus_info = mlxsw_bus_info;
658
659	err = mlxsw_m_fw_rev_validate(mlxsw_m);
660	if (err)
661		return err;
662
663	err = mlxsw_m_base_mac_get(mlxsw_m);
664	if (err) {
665		dev_err(mlxsw_m->bus_info->dev, "Failed to get base mac\n");
666		return err;
667	}
668
669	err = mlxsw_m_linecards_init(mlxsw_m);
670	if (err) {
671		dev_err(mlxsw_m->bus_info->dev, "Failed to create line cards\n");
672		return err;
673	}
674
675	err = mlxsw_linecards_event_ops_register(mlxsw_core,
676						 &mlxsw_m_event_ops, mlxsw_m);
677	if (err) {
678		dev_err(mlxsw_m->bus_info->dev, "Failed to register line cards operations\n");
679		goto linecards_event_ops_register;
680	}
681
682	err = mlxsw_m_ports_create(mlxsw_m);
683	if (err) {
684		dev_err(mlxsw_m->bus_info->dev, "Failed to create ports\n");
685		goto err_ports_create;
686	}
687
688	return 0;
689
690err_ports_create:
691	mlxsw_linecards_event_ops_unregister(mlxsw_core,
692					     &mlxsw_m_event_ops, mlxsw_m);
693linecards_event_ops_register:
694	mlxsw_m_linecards_fini(mlxsw_m);
695	return err;
696}
697
698static void mlxsw_m_fini(struct mlxsw_core *mlxsw_core)
699{
700	struct mlxsw_m *mlxsw_m = mlxsw_core_driver_priv(mlxsw_core);
701
702	mlxsw_m_ports_remove(mlxsw_m);
703	mlxsw_linecards_event_ops_unregister(mlxsw_core,
704					     &mlxsw_m_event_ops, mlxsw_m);
705	mlxsw_m_linecards_fini(mlxsw_m);
706}
707
708static const struct mlxsw_config_profile mlxsw_m_config_profile;
709
710static struct mlxsw_driver mlxsw_m_driver = {
711	.kind			= mlxsw_m_driver_name,
712	.priv_size		= sizeof(struct mlxsw_m),
713	.init			= mlxsw_m_init,
714	.fini			= mlxsw_m_fini,
715	.ports_remove_selected	= mlxsw_m_ports_remove_selected,
716	.profile		= &mlxsw_m_config_profile,
717};
718
719static const struct i2c_device_id mlxsw_m_i2c_id[] = {
720	{ "mlxsw_minimal" },
721	{ }
722};
723
724static struct i2c_driver mlxsw_m_i2c_driver = {
725	.driver.name = "mlxsw_minimal",
726	.id_table = mlxsw_m_i2c_id,
727};
728
729static int __init mlxsw_m_module_init(void)
730{
731	int err;
732
733	err = mlxsw_core_driver_register(&mlxsw_m_driver);
734	if (err)
735		return err;
736
737	err = mlxsw_i2c_driver_register(&mlxsw_m_i2c_driver);
738	if (err)
739		goto err_i2c_driver_register;
740
741	return 0;
742
743err_i2c_driver_register:
744	mlxsw_core_driver_unregister(&mlxsw_m_driver);
745
746	return err;
747}
748
749static void __exit mlxsw_m_module_exit(void)
750{
751	mlxsw_i2c_driver_unregister(&mlxsw_m_i2c_driver);
752	mlxsw_core_driver_unregister(&mlxsw_m_driver);
753}
754
755module_init(mlxsw_m_module_init);
756module_exit(mlxsw_m_module_exit);
757
758MODULE_LICENSE("Dual BSD/GPL");
759MODULE_AUTHOR("Vadim Pasternak <vadimp@mellanox.com>");
760MODULE_DESCRIPTION("Mellanox minimal driver");
761MODULE_DEVICE_TABLE(i2c, mlxsw_m_i2c_id);
~/ Read-only file preview.