1 // SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0-or-later
2 /*
3 * Copyright 2008 - 2015 Freescale Semiconductor Inc.
4 */
5
6 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
7
8 #include <linux/init.h>
9 #include <linux/module.h>
10 #include <linux/of_address.h>
11 #include <linux/of_platform.h>
12 #include <linux/of_net.h>
13 #include <linux/of_mdio.h>
14 #include <linux/device.h>
15 #include <linux/phy.h>
16 #include <linux/netdevice.h>
17 #include <linux/phy_fixed.h>
18 #include <linux/phylink.h>
19 #include <linux/etherdevice.h>
20 #include <linux/libfdt_env.h>
21 #include <linux/platform_device.h>
22
23 #include "mac.h"
24 #include "fman_mac.h"
25 #include "fman_dtsec.h"
26 #include "fman_tgec.h"
27 #include "fman_memac.h"
28
29 MODULE_LICENSE("Dual BSD/GPL");
30 MODULE_DESCRIPTION("FSL FMan MAC API based driver");
31
32 struct mac_priv_s {
33 u8 cell_index;
34 struct fman *fman;
35 /* List of multicast addresses */
36 struct list_head mc_addr_list;
37 struct platform_device *eth_dev;
38 u16 speed;
39 };
40
41 struct mac_address {
42 u8 addr[ETH_ALEN];
43 struct list_head list;
44 };
45
mac_exception(struct mac_device * mac_dev,enum fman_mac_exceptions ex)46 static void mac_exception(struct mac_device *mac_dev,
47 enum fman_mac_exceptions ex)
48 {
49 if (ex == FM_MAC_EX_10G_RX_FIFO_OVFL) {
50 /* don't flag RX FIFO after the first */
51 mac_dev->set_exception(mac_dev->fman_mac,
52 FM_MAC_EX_10G_RX_FIFO_OVFL, false);
53 dev_err(mac_dev->dev, "10G MAC got RX FIFO Error = %x\n", ex);
54 }
55
56 dev_dbg(mac_dev->dev, "%s:%s() -> %d\n", KBUILD_BASENAME ".c",
57 __func__, ex);
58 }
59
fman_set_multi(struct net_device * net_dev,struct mac_device * mac_dev)60 int fman_set_multi(struct net_device *net_dev, struct mac_device *mac_dev)
61 {
62 struct mac_priv_s *priv;
63 struct mac_address *old_addr, *tmp;
64 struct netdev_hw_addr *ha;
65 int err;
66 enet_addr_t *addr;
67
68 priv = mac_dev->priv;
69
70 /* Clear previous address list */
71 list_for_each_entry_safe(old_addr, tmp, &priv->mc_addr_list, list) {
72 addr = (enet_addr_t *)old_addr->addr;
73 err = mac_dev->remove_hash_mac_addr(mac_dev->fman_mac, addr);
74 if (err < 0)
75 return err;
76
77 list_del(&old_addr->list);
78 kfree(old_addr);
79 }
80
81 /* Add all the addresses from the new list */
82 netdev_for_each_mc_addr(ha, net_dev) {
83 addr = (enet_addr_t *)ha->addr;
84 err = mac_dev->add_hash_mac_addr(mac_dev->fman_mac, addr);
85 if (err < 0)
86 return err;
87
88 tmp = kmalloc(sizeof(*tmp), GFP_ATOMIC);
89 if (!tmp)
90 return -ENOMEM;
91
92 ether_addr_copy(tmp->addr, ha->addr);
93 list_add(&tmp->list, &priv->mc_addr_list);
94 }
95 return 0;
96 }
97
98 static DEFINE_MUTEX(eth_lock);
99
dpaa_eth_add_device(int fman_id,struct mac_device * mac_dev)100 static struct platform_device *dpaa_eth_add_device(int fman_id,
101 struct mac_device *mac_dev)
102 {
103 struct platform_device *pdev;
104 struct dpaa_eth_data data;
105 struct mac_priv_s *priv;
106 static int dpaa_eth_dev_cnt;
107 int ret;
108
109 priv = mac_dev->priv;
110
111 data.mac_dev = mac_dev;
112 data.mac_hw_id = priv->cell_index;
113 data.fman_hw_id = fman_id;
114
115 mutex_lock(ð_lock);
116 pdev = platform_device_alloc("dpaa-ethernet", dpaa_eth_dev_cnt);
117 if (!pdev) {
118 ret = -ENOMEM;
119 goto no_mem;
120 }
121
122 pdev->dev.parent = mac_dev->dev;
123
124 ret = platform_device_add_data(pdev, &data, sizeof(data));
125 if (ret)
126 goto err;
127
128 ret = platform_device_add(pdev);
129 if (ret)
130 goto err;
131
132 dpaa_eth_dev_cnt++;
133 mutex_unlock(ð_lock);
134
135 return pdev;
136
137 err:
138 platform_device_put(pdev);
139 no_mem:
140 mutex_unlock(ð_lock);
141
142 return ERR_PTR(ret);
143 }
144
145 static const struct of_device_id mac_match[] = {
146 { .compatible = "fsl,fman-dtsec", .data = dtsec_initialization },
147 { .compatible = "fsl,fman-xgec", .data = tgec_initialization },
148 { .compatible = "fsl,fman-memac", .data = memac_initialization },
149 {}
150 };
151 MODULE_DEVICE_TABLE(of, mac_match);
152
mac_probe(struct platform_device * _of_dev)153 static int mac_probe(struct platform_device *_of_dev)
154 {
155 int err, i, nph;
156 int (*init)(struct mac_device *mac_dev, struct device_node *mac_node,
157 struct fman_mac_params *params);
158 struct device *dev;
159 struct device_node *mac_node, *dev_node;
160 struct mac_device *mac_dev;
161 struct platform_device *of_dev;
162 struct mac_priv_s *priv;
163 struct fman_mac_params params;
164 u32 val;
165 u8 fman_id;
166 phy_interface_t phy_if;
167
168 dev = &_of_dev->dev;
169 mac_node = dev->of_node;
170 init = of_device_get_match_data(dev);
171
172 mac_dev = devm_kzalloc(dev, sizeof(*mac_dev), GFP_KERNEL);
173 if (!mac_dev)
174 return -ENOMEM;
175 priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
176 if (!priv)
177 return -ENOMEM;
178 platform_set_drvdata(_of_dev, mac_dev);
179
180 /* Save private information */
181 mac_dev->priv = priv;
182 mac_dev->dev = dev;
183
184 INIT_LIST_HEAD(&priv->mc_addr_list);
185
186 /* Get the FM node */
187 dev_node = of_get_parent(mac_node);
188 if (!dev_node) {
189 dev_err(dev, "of_get_parent(%pOF) failed\n",
190 mac_node);
191 return -EINVAL;
192 }
193
194 of_dev = of_find_device_by_node(dev_node);
195 if (!of_dev) {
196 dev_err(dev, "of_find_device_by_node(%pOF) failed\n", dev_node);
197 err = -EINVAL;
198 goto _return_of_node_put;
199 }
200 mac_dev->fman_dev = &of_dev->dev;
201
202 /* Get the FMan cell-index */
203 err = of_property_read_u32(dev_node, "cell-index", &val);
204 if (err) {
205 dev_err(dev, "failed to read cell-index for %pOF\n", dev_node);
206 err = -EINVAL;
207 goto _return_dev_put;
208 }
209 /* cell-index 0 => FMan id 1 */
210 fman_id = (u8)(val + 1);
211
212 priv->fman = fman_bind(mac_dev->fman_dev);
213 if (!priv->fman) {
214 dev_err(dev, "fman_bind(%pOF) failed\n", dev_node);
215 err = -ENODEV;
216 goto _return_dev_put;
217 }
218
219 /* Two references have been taken in of_find_device_by_node()
220 * and fman_bind(). Release one of them here. The second one
221 * will be released in mac_remove().
222 */
223 put_device(mac_dev->fman_dev);
224 of_node_put(dev_node);
225 dev_node = NULL;
226
227 /* Get the address of the memory mapped registers */
228 mac_dev->res = platform_get_mem_or_io(_of_dev, 0);
229 if (!mac_dev->res) {
230 dev_err(dev, "could not get registers\n");
231 err = -EINVAL;
232 goto _return_dev_put;
233 }
234
235 err = devm_request_resource(dev, fman_get_mem_region(priv->fman),
236 mac_dev->res);
237 if (err) {
238 dev_err_probe(dev, err, "could not request resource\n");
239 goto _return_dev_put;
240 }
241
242 mac_dev->vaddr = devm_ioremap(dev, mac_dev->res->start,
243 resource_size(mac_dev->res));
244 if (!mac_dev->vaddr) {
245 dev_err(dev, "devm_ioremap() failed\n");
246 err = -EIO;
247 goto _return_dev_put;
248 }
249
250 if (!of_device_is_available(mac_node)) {
251 err = -ENODEV;
252 goto _return_dev_put;
253 }
254
255 /* Get the cell-index */
256 err = of_property_read_u32(mac_node, "cell-index", &val);
257 if (err) {
258 dev_err(dev, "failed to read cell-index for %pOF\n", mac_node);
259 err = -EINVAL;
260 goto _return_dev_put;
261 }
262 if (val >= MAX_NUM_OF_MACS) {
263 dev_err(dev, "cell-index value is too big for %pOF\n", mac_node);
264 err = -EINVAL;
265 goto _return_dev_put;
266 }
267 priv->cell_index = (u8)val;
268
269 /* Get the MAC address */
270 err = of_get_mac_address(mac_node, mac_dev->addr);
271 if (err)
272 dev_warn(dev, "of_get_mac_address(%pOF) failed\n", mac_node);
273
274 /* Get the port handles */
275 nph = of_count_phandle_with_args(mac_node, "fsl,fman-ports", NULL);
276 if (unlikely(nph < 0)) {
277 dev_err(dev, "of_count_phandle_with_args(%pOF, fsl,fman-ports) failed\n",
278 mac_node);
279 err = nph;
280 goto _return_dev_put;
281 }
282
283 if (nph != ARRAY_SIZE(mac_dev->port)) {
284 dev_err(dev, "Not supported number of fman-ports handles of mac node %pOF from device tree\n",
285 mac_node);
286 err = -EINVAL;
287 goto _return_dev_put;
288 }
289
290 /* PORT_NUM determines the size of the port array */
291 for (i = 0; i < PORT_NUM; i++) {
292 /* Find the port node */
293 dev_node = of_parse_phandle(mac_node, "fsl,fman-ports", i);
294 if (!dev_node) {
295 dev_err(dev, "of_parse_phandle(%pOF, fsl,fman-ports) failed\n",
296 mac_node);
297 err = -EINVAL;
298 goto _return_dev_arr_put;
299 }
300
301 of_dev = of_find_device_by_node(dev_node);
302 if (!of_dev) {
303 dev_err(dev, "of_find_device_by_node(%pOF) failed\n",
304 dev_node);
305 err = -EINVAL;
306 goto _return_dev_arr_put;
307 }
308 mac_dev->fman_port_devs[i] = &of_dev->dev;
309
310 mac_dev->port[i] = fman_port_bind(mac_dev->fman_port_devs[i]);
311 if (!mac_dev->port[i]) {
312 dev_err(dev, "dev_get_drvdata(%pOF) failed\n",
313 dev_node);
314 err = -EINVAL;
315 goto _return_dev_arr_put;
316 }
317 /* Two references have been taken in of_find_device_by_node()
318 * and fman_port_bind(). Release one of them here. The second
319 * one will be released in mac_remove().
320 */
321 put_device(mac_dev->fman_port_devs[i]);
322 of_node_put(dev_node);
323 dev_node = NULL;
324 }
325
326 /* Get the PHY connection type */
327 err = of_get_phy_mode(mac_node, &phy_if);
328 if (err) {
329 dev_warn(dev,
330 "of_get_phy_mode() for %pOF failed. Defaulting to SGMII\n",
331 mac_node);
332 phy_if = PHY_INTERFACE_MODE_SGMII;
333 }
334 mac_dev->phy_if = phy_if;
335
336 params.mac_id = priv->cell_index;
337 params.fm = (void *)priv->fman;
338 params.exception_cb = mac_exception;
339 params.event_cb = mac_exception;
340
341 err = init(mac_dev, mac_node, ¶ms);
342 if (err < 0)
343 goto _return_dev_arr_put;
344
345 if (!is_zero_ether_addr(mac_dev->addr))
346 dev_info(dev, "FMan MAC address: %pM\n", mac_dev->addr);
347
348 priv->eth_dev = dpaa_eth_add_device(fman_id, mac_dev);
349 if (IS_ERR(priv->eth_dev)) {
350 err = PTR_ERR(priv->eth_dev);
351 dev_err(dev, "failed to add Ethernet platform device for MAC %d\n",
352 priv->cell_index);
353 priv->eth_dev = NULL;
354 }
355
356 return err;
357
358 _return_dev_arr_put:
359 /* mac_dev is kzalloc'ed */
360 for (i = 0; i < PORT_NUM; i++)
361 put_device(mac_dev->fman_port_devs[i]);
362 _return_dev_put:
363 put_device(mac_dev->fman_dev);
364 _return_of_node_put:
365 of_node_put(dev_node);
366 return err;
367 }
368
mac_remove(struct platform_device * pdev)369 static void mac_remove(struct platform_device *pdev)
370 {
371 struct mac_device *mac_dev = platform_get_drvdata(pdev);
372 int i;
373
374 for (i = 0; i < PORT_NUM; i++)
375 put_device(mac_dev->fman_port_devs[i]);
376 put_device(mac_dev->fman_dev);
377
378 platform_device_unregister(mac_dev->priv->eth_dev);
379 }
380
381 static struct platform_driver mac_driver = {
382 .driver = {
383 .name = KBUILD_MODNAME,
384 .of_match_table = mac_match,
385 },
386 .probe = mac_probe,
387 .remove_new = mac_remove,
388 };
389
390 builtin_platform_driver(mac_driver);
391