File Index
Files and directories
Sign in
FILE

mac.c

File preview with syntax highlighting.

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