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