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