forked from ~ljy/RK356X_SDK_RELEASE

hc
2024-12-19 9370bb92b2d16684ee45cf24e879c93c509162da
kernel/drivers/net/ethernet/mellanox/mlxsw/minimal.c
....@@ -1,6 +1,9 @@
11 // SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0
2
-/* Copyright (c) 2016-2018 Mellanox Technologies. All rights reserved */
2
+/* Copyright (c) 2016-2019 Mellanox Technologies. All rights reserved */
33
4
+#include <linux/netdevice.h>
5
+#include <linux/etherdevice.h>
6
+#include <linux/ethtool.h>
47 #include <linux/i2c.h>
58 #include <linux/kernel.h>
69 #include <linux/module.h>
....@@ -8,59 +11,439 @@
811 #include <linux/types.h>
912
1013 #include "core.h"
14
+#include "core_env.h"
1115 #include "i2c.h"
1216
13
-static const char mlxsw_minimal_driver_name[] = "mlxsw_minimal";
17
+static const char mlxsw_m_driver_name[] = "mlxsw_minimal";
1418
15
-static const struct mlxsw_config_profile mlxsw_minimal_config_profile;
19
+#define MLXSW_M_FWREV_MINOR 2000
20
+#define MLXSW_M_FWREV_SUBMINOR 1886
1621
17
-static struct mlxsw_driver mlxsw_minimal_driver = {
18
- .kind = mlxsw_minimal_driver_name,
19
- .priv_size = 1,
20
- .profile = &mlxsw_minimal_config_profile,
22
+static const struct mlxsw_fw_rev mlxsw_m_fw_rev = {
23
+ .minor = MLXSW_M_FWREV_MINOR,
24
+ .subminor = MLXSW_M_FWREV_SUBMINOR,
2125 };
2226
23
-static const struct i2c_device_id mlxsw_minimal_i2c_id[] = {
27
+struct mlxsw_m_port;
28
+
29
+struct 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
+
38
+struct mlxsw_m_port {
39
+ struct net_device *dev;
40
+ struct mlxsw_m *mlxsw_m;
41
+ u8 local_port;
42
+ u8 module;
43
+};
44
+
45
+static 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
+
57
+static int mlxsw_m_port_dummy_open_stop(struct net_device *dev)
58
+{
59
+ return 0;
60
+}
61
+
62
+static struct devlink_port *
63
+mlxsw_m_port_get_devlink_port(struct net_device *dev)
64
+{
65
+ struct mlxsw_m_port *mlxsw_m_port = netdev_priv(dev);
66
+ struct mlxsw_m *mlxsw_m = mlxsw_m_port->mlxsw_m;
67
+
68
+ return mlxsw_core_port_devlink_port_get(mlxsw_m->core,
69
+ mlxsw_m_port->local_port);
70
+}
71
+
72
+static const struct net_device_ops mlxsw_m_port_netdev_ops = {
73
+ .ndo_open = mlxsw_m_port_dummy_open_stop,
74
+ .ndo_stop = mlxsw_m_port_dummy_open_stop,
75
+ .ndo_get_devlink_port = mlxsw_m_port_get_devlink_port,
76
+};
77
+
78
+static void mlxsw_m_module_get_drvinfo(struct net_device *dev,
79
+ struct ethtool_drvinfo *drvinfo)
80
+{
81
+ struct mlxsw_m_port *mlxsw_m_port = netdev_priv(dev);
82
+ struct mlxsw_m *mlxsw_m = mlxsw_m_port->mlxsw_m;
83
+
84
+ strlcpy(drvinfo->driver, mlxsw_m->bus_info->device_kind,
85
+ sizeof(drvinfo->driver));
86
+ snprintf(drvinfo->fw_version, sizeof(drvinfo->fw_version),
87
+ "%d.%d.%d",
88
+ mlxsw_m->bus_info->fw_rev.major,
89
+ mlxsw_m->bus_info->fw_rev.minor,
90
+ mlxsw_m->bus_info->fw_rev.subminor);
91
+ strlcpy(drvinfo->bus_info, mlxsw_m->bus_info->device_name,
92
+ sizeof(drvinfo->bus_info));
93
+}
94
+
95
+static int mlxsw_m_get_module_info(struct net_device *netdev,
96
+ struct ethtool_modinfo *modinfo)
97
+{
98
+ struct mlxsw_m_port *mlxsw_m_port = netdev_priv(netdev);
99
+ struct mlxsw_core *core = mlxsw_m_port->mlxsw_m->core;
100
+
101
+ return mlxsw_env_get_module_info(core, mlxsw_m_port->module, modinfo);
102
+}
103
+
104
+static int
105
+mlxsw_m_get_module_eeprom(struct net_device *netdev, struct ethtool_eeprom *ee,
106
+ u8 *data)
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_eeprom(netdev, core, mlxsw_m_port->module,
112
+ ee, data);
113
+}
114
+
115
+static const struct ethtool_ops mlxsw_m_port_ethtool_ops = {
116
+ .get_drvinfo = mlxsw_m_module_get_drvinfo,
117
+ .get_module_info = mlxsw_m_get_module_info,
118
+ .get_module_eeprom = mlxsw_m_get_module_eeprom,
119
+};
120
+
121
+static int
122
+mlxsw_m_port_module_info_get(struct mlxsw_m *mlxsw_m, u8 local_port,
123
+ u8 *p_module, u8 *p_width)
124
+{
125
+ char pmlp_pl[MLXSW_REG_PMLP_LEN];
126
+ int err;
127
+
128
+ mlxsw_reg_pmlp_pack(pmlp_pl, local_port);
129
+ err = mlxsw_reg_query(mlxsw_m->core, MLXSW_REG(pmlp), pmlp_pl);
130
+ if (err)
131
+ return err;
132
+ *p_module = mlxsw_reg_pmlp_module_get(pmlp_pl, 0);
133
+ *p_width = mlxsw_reg_pmlp_width_get(pmlp_pl);
134
+
135
+ return 0;
136
+}
137
+
138
+static int
139
+mlxsw_m_port_dev_addr_get(struct mlxsw_m_port *mlxsw_m_port)
140
+{
141
+ struct mlxsw_m *mlxsw_m = mlxsw_m_port->mlxsw_m;
142
+ struct net_device *dev = mlxsw_m_port->dev;
143
+ char ppad_pl[MLXSW_REG_PPAD_LEN];
144
+ int err;
145
+
146
+ mlxsw_reg_ppad_pack(ppad_pl, false, 0);
147
+ err = mlxsw_reg_query(mlxsw_m->core, MLXSW_REG(ppad), ppad_pl);
148
+ if (err)
149
+ return err;
150
+ mlxsw_reg_ppad_mac_memcpy_from(ppad_pl, dev->dev_addr);
151
+ /* The last byte value in base mac address is guaranteed
152
+ * to be such it does not overflow when adding local_port
153
+ * value.
154
+ */
155
+ dev->dev_addr[ETH_ALEN - 1] += mlxsw_m_port->module + 1;
156
+ return 0;
157
+}
158
+
159
+static int
160
+mlxsw_m_port_create(struct mlxsw_m *mlxsw_m, u8 local_port, u8 module)
161
+{
162
+ struct mlxsw_m_port *mlxsw_m_port;
163
+ struct net_device *dev;
164
+ int err;
165
+
166
+ err = mlxsw_core_port_init(mlxsw_m->core, local_port,
167
+ module + 1, false, 0, false,
168
+ 0, mlxsw_m->base_mac,
169
+ sizeof(mlxsw_m->base_mac));
170
+ if (err) {
171
+ dev_err(mlxsw_m->bus_info->dev, "Port %d: Failed to init core port\n",
172
+ local_port);
173
+ return err;
174
+ }
175
+
176
+ dev = alloc_etherdev(sizeof(struct mlxsw_m_port));
177
+ if (!dev) {
178
+ err = -ENOMEM;
179
+ goto err_alloc_etherdev;
180
+ }
181
+
182
+ SET_NETDEV_DEV(dev, mlxsw_m->bus_info->dev);
183
+ dev_net_set(dev, mlxsw_core_net(mlxsw_m->core));
184
+ mlxsw_m_port = netdev_priv(dev);
185
+ mlxsw_m_port->dev = dev;
186
+ mlxsw_m_port->mlxsw_m = mlxsw_m;
187
+ mlxsw_m_port->local_port = local_port;
188
+ mlxsw_m_port->module = module;
189
+
190
+ dev->netdev_ops = &mlxsw_m_port_netdev_ops;
191
+ dev->ethtool_ops = &mlxsw_m_port_ethtool_ops;
192
+
193
+ err = mlxsw_m_port_dev_addr_get(mlxsw_m_port);
194
+ if (err) {
195
+ dev_err(mlxsw_m->bus_info->dev, "Port %d: Unable to get port mac address\n",
196
+ mlxsw_m_port->local_port);
197
+ goto err_dev_addr_get;
198
+ }
199
+
200
+ netif_carrier_off(dev);
201
+ mlxsw_m->ports[local_port] = mlxsw_m_port;
202
+ err = register_netdev(dev);
203
+ if (err) {
204
+ dev_err(mlxsw_m->bus_info->dev, "Port %d: Failed to register netdev\n",
205
+ mlxsw_m_port->local_port);
206
+ goto err_register_netdev;
207
+ }
208
+
209
+ mlxsw_core_port_eth_set(mlxsw_m->core, mlxsw_m_port->local_port,
210
+ mlxsw_m_port, dev);
211
+
212
+ return 0;
213
+
214
+err_register_netdev:
215
+ mlxsw_m->ports[local_port] = NULL;
216
+err_dev_addr_get:
217
+ free_netdev(dev);
218
+err_alloc_etherdev:
219
+ mlxsw_core_port_fini(mlxsw_m->core, local_port);
220
+ return err;
221
+}
222
+
223
+static void mlxsw_m_port_remove(struct mlxsw_m *mlxsw_m, u8 local_port)
224
+{
225
+ struct mlxsw_m_port *mlxsw_m_port = mlxsw_m->ports[local_port];
226
+
227
+ mlxsw_core_port_clear(mlxsw_m->core, local_port, mlxsw_m);
228
+ unregister_netdev(mlxsw_m_port->dev); /* This calls ndo_stop */
229
+ mlxsw_m->ports[local_port] = NULL;
230
+ free_netdev(mlxsw_m_port->dev);
231
+ mlxsw_core_port_fini(mlxsw_m->core, local_port);
232
+}
233
+
234
+static int mlxsw_m_port_module_map(struct mlxsw_m *mlxsw_m, u8 local_port,
235
+ u8 *last_module)
236
+{
237
+ unsigned int max_ports = mlxsw_core_max_ports(mlxsw_m->core);
238
+ u8 module, width;
239
+ int err;
240
+
241
+ /* Fill out to local port mapping array */
242
+ err = mlxsw_m_port_module_info_get(mlxsw_m, local_port, &module,
243
+ &width);
244
+ if (err)
245
+ return err;
246
+
247
+ if (!width)
248
+ return 0;
249
+ /* Skip, if port belongs to the cluster */
250
+ if (module == *last_module)
251
+ return 0;
252
+ *last_module = module;
253
+
254
+ if (WARN_ON_ONCE(module >= max_ports))
255
+ return -EINVAL;
256
+ mlxsw_m->module_to_port[module] = ++mlxsw_m->max_ports;
257
+
258
+ return 0;
259
+}
260
+
261
+static void mlxsw_m_port_module_unmap(struct mlxsw_m *mlxsw_m, u8 module)
262
+{
263
+ mlxsw_m->module_to_port[module] = -1;
264
+}
265
+
266
+static int mlxsw_m_ports_create(struct mlxsw_m *mlxsw_m)
267
+{
268
+ unsigned int max_ports = mlxsw_core_max_ports(mlxsw_m->core);
269
+ u8 last_module = max_ports;
270
+ int i;
271
+ int err;
272
+
273
+ mlxsw_m->ports = kcalloc(max_ports, sizeof(*mlxsw_m->ports),
274
+ GFP_KERNEL);
275
+ if (!mlxsw_m->ports)
276
+ return -ENOMEM;
277
+
278
+ mlxsw_m->module_to_port = kmalloc_array(max_ports, sizeof(int),
279
+ GFP_KERNEL);
280
+ if (!mlxsw_m->module_to_port) {
281
+ err = -ENOMEM;
282
+ goto err_module_to_port_alloc;
283
+ }
284
+
285
+ /* Invalidate the entries of module to local port mapping array */
286
+ for (i = 0; i < max_ports; i++)
287
+ mlxsw_m->module_to_port[i] = -1;
288
+
289
+ /* Fill out module to local port mapping array */
290
+ for (i = 1; i < max_ports; i++) {
291
+ err = mlxsw_m_port_module_map(mlxsw_m, i, &last_module);
292
+ if (err)
293
+ goto err_module_to_port_map;
294
+ }
295
+
296
+ /* Create port objects for each valid entry */
297
+ for (i = 0; i < mlxsw_m->max_ports; i++) {
298
+ if (mlxsw_m->module_to_port[i] > 0) {
299
+ err = mlxsw_m_port_create(mlxsw_m,
300
+ mlxsw_m->module_to_port[i],
301
+ i);
302
+ if (err)
303
+ goto err_module_to_port_create;
304
+ }
305
+ }
306
+
307
+ return 0;
308
+
309
+err_module_to_port_create:
310
+ for (i--; i >= 0; i--) {
311
+ if (mlxsw_m->module_to_port[i] > 0)
312
+ mlxsw_m_port_remove(mlxsw_m,
313
+ mlxsw_m->module_to_port[i]);
314
+ }
315
+ i = max_ports;
316
+err_module_to_port_map:
317
+ for (i--; i > 0; i--)
318
+ mlxsw_m_port_module_unmap(mlxsw_m, i);
319
+ kfree(mlxsw_m->module_to_port);
320
+err_module_to_port_alloc:
321
+ kfree(mlxsw_m->ports);
322
+ return err;
323
+}
324
+
325
+static void mlxsw_m_ports_remove(struct mlxsw_m *mlxsw_m)
326
+{
327
+ int i;
328
+
329
+ for (i = 0; i < mlxsw_m->max_ports; i++) {
330
+ if (mlxsw_m->module_to_port[i] > 0) {
331
+ mlxsw_m_port_remove(mlxsw_m,
332
+ mlxsw_m->module_to_port[i]);
333
+ mlxsw_m_port_module_unmap(mlxsw_m, i);
334
+ }
335
+ }
336
+
337
+ kfree(mlxsw_m->module_to_port);
338
+ kfree(mlxsw_m->ports);
339
+}
340
+
341
+static int mlxsw_m_fw_rev_validate(struct mlxsw_m *mlxsw_m)
342
+{
343
+ const struct mlxsw_fw_rev *rev = &mlxsw_m->bus_info->fw_rev;
344
+
345
+ /* Validate driver and FW are compatible.
346
+ * Do not check major version, since it defines chip type, while
347
+ * driver is supposed to support any type.
348
+ */
349
+ if (mlxsw_core_fw_rev_minor_subminor_validate(rev, &mlxsw_m_fw_rev))
350
+ return 0;
351
+
352
+ dev_err(mlxsw_m->bus_info->dev, "The firmware version %d.%d.%d is incompatible with the driver (required >= %d.%d.%d)\n",
353
+ rev->major, rev->minor, rev->subminor, rev->major,
354
+ mlxsw_m_fw_rev.minor, mlxsw_m_fw_rev.subminor);
355
+
356
+ return -EINVAL;
357
+}
358
+
359
+static int mlxsw_m_init(struct mlxsw_core *mlxsw_core,
360
+ const struct mlxsw_bus_info *mlxsw_bus_info,
361
+ struct netlink_ext_ack *extack)
362
+{
363
+ struct mlxsw_m *mlxsw_m = mlxsw_core_driver_priv(mlxsw_core);
364
+ int err;
365
+
366
+ mlxsw_m->core = mlxsw_core;
367
+ mlxsw_m->bus_info = mlxsw_bus_info;
368
+
369
+ err = mlxsw_m_fw_rev_validate(mlxsw_m);
370
+ if (err)
371
+ return err;
372
+
373
+ err = mlxsw_m_base_mac_get(mlxsw_m);
374
+ if (err) {
375
+ dev_err(mlxsw_m->bus_info->dev, "Failed to get base mac\n");
376
+ return err;
377
+ }
378
+
379
+ err = mlxsw_m_ports_create(mlxsw_m);
380
+ if (err) {
381
+ dev_err(mlxsw_m->bus_info->dev, "Failed to create ports\n");
382
+ return err;
383
+ }
384
+
385
+ return 0;
386
+}
387
+
388
+static void mlxsw_m_fini(struct mlxsw_core *mlxsw_core)
389
+{
390
+ struct mlxsw_m *mlxsw_m = mlxsw_core_driver_priv(mlxsw_core);
391
+
392
+ mlxsw_m_ports_remove(mlxsw_m);
393
+}
394
+
395
+static const struct mlxsw_config_profile mlxsw_m_config_profile;
396
+
397
+static struct mlxsw_driver mlxsw_m_driver = {
398
+ .kind = mlxsw_m_driver_name,
399
+ .priv_size = sizeof(struct mlxsw_m),
400
+ .init = mlxsw_m_init,
401
+ .fini = mlxsw_m_fini,
402
+ .profile = &mlxsw_m_config_profile,
403
+ .res_query_enabled = true,
404
+};
405
+
406
+static const struct i2c_device_id mlxsw_m_i2c_id[] = {
24407 { "mlxsw_minimal", 0},
25408 { },
26409 };
27410
28
-static struct i2c_driver mlxsw_minimal_i2c_driver = {
411
+static struct i2c_driver mlxsw_m_i2c_driver = {
29412 .driver.name = "mlxsw_minimal",
30413 .class = I2C_CLASS_HWMON,
31
- .id_table = mlxsw_minimal_i2c_id,
414
+ .id_table = mlxsw_m_i2c_id,
32415 };
33416
34
-static int __init mlxsw_minimal_module_init(void)
417
+static int __init mlxsw_m_module_init(void)
35418 {
36419 int err;
37420
38
- err = mlxsw_core_driver_register(&mlxsw_minimal_driver);
421
+ err = mlxsw_core_driver_register(&mlxsw_m_driver);
39422 if (err)
40423 return err;
41424
42
- err = mlxsw_i2c_driver_register(&mlxsw_minimal_i2c_driver);
425
+ err = mlxsw_i2c_driver_register(&mlxsw_m_i2c_driver);
43426 if (err)
44427 goto err_i2c_driver_register;
45428
46429 return 0;
47430
48431 err_i2c_driver_register:
49
- mlxsw_core_driver_unregister(&mlxsw_minimal_driver);
432
+ mlxsw_core_driver_unregister(&mlxsw_m_driver);
50433
51434 return err;
52435 }
53436
54
-static void __exit mlxsw_minimal_module_exit(void)
437
+static void __exit mlxsw_m_module_exit(void)
55438 {
56
- mlxsw_i2c_driver_unregister(&mlxsw_minimal_i2c_driver);
57
- mlxsw_core_driver_unregister(&mlxsw_minimal_driver);
439
+ mlxsw_i2c_driver_unregister(&mlxsw_m_i2c_driver);
440
+ mlxsw_core_driver_unregister(&mlxsw_m_driver);
58441 }
59442
60
-module_init(mlxsw_minimal_module_init);
61
-module_exit(mlxsw_minimal_module_exit);
443
+module_init(mlxsw_m_module_init);
444
+module_exit(mlxsw_m_module_exit);
62445
63446 MODULE_LICENSE("Dual BSD/GPL");
64447 MODULE_AUTHOR("Vadim Pasternak <vadimp@mellanox.com>");
65448 MODULE_DESCRIPTION("Mellanox minimal driver");
66
-MODULE_DEVICE_TABLE(i2c, mlxsw_minimal_i2c_id);
449
+MODULE_DEVICE_TABLE(i2c, mlxsw_m_i2c_id);