xref: /openbmc/linux/drivers/net/ethernet/freescale/fman/mac.c (revision 6ff9768a3144c846462de27ebedeb8fa694b87ae)
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 
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 
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 
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(&eth_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(&eth_lock);
134 
135 	return pdev;
136 
137 err:
138 	platform_device_put(pdev);
139 no_mem:
140 	mutex_unlock(&eth_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 
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, &params);
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 
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