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