Linux kernel mirror (for testing)
git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel
os
linux
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(ð_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(ð_lock);
92
93 return pdev;
94
95err:
96 platform_device_put(pdev);
97no_mem:
98 mutex_unlock(ð_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, ¶ms);
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);