1 | #include <machine/rtems-bsd-kernel-space.h> |
---|
2 | |
---|
3 | #include <rtems/bsd/local/opt_dpaa.h> |
---|
4 | |
---|
5 | /* Copyright 2008-2015 Freescale Semiconductor, Inc. |
---|
6 | * |
---|
7 | * Redistribution and use in source and binary forms, with or without |
---|
8 | * modification, are permitted provided that the following conditions are met: |
---|
9 | * * Redistributions of source code must retain the above copyright |
---|
10 | * notice, this list of conditions and the following disclaimer. |
---|
11 | * * Redistributions in binary form must reproduce the above copyright |
---|
12 | * notice, this list of conditions and the following disclaimer in the |
---|
13 | * documentation and/or other materials provided with the distribution. |
---|
14 | * * Neither the name of Freescale Semiconductor nor the |
---|
15 | * names of its contributors may be used to endorse or promote products |
---|
16 | * derived from this software without specific prior written permission. |
---|
17 | * |
---|
18 | * |
---|
19 | * ALTERNATIVELY, this software may be distributed under the terms of the |
---|
20 | * GNU General Public License ("GPL") as published by the Free Software |
---|
21 | * Foundation, either version 2 of that License or (at your option) any |
---|
22 | * later version. |
---|
23 | * |
---|
24 | * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY |
---|
25 | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED |
---|
26 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE |
---|
27 | * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY |
---|
28 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES |
---|
29 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; |
---|
30 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND |
---|
31 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
---|
32 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS |
---|
33 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
---|
34 | */ |
---|
35 | |
---|
36 | #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt |
---|
37 | |
---|
38 | #ifdef __rtems__ |
---|
39 | #include <sys/types.h> |
---|
40 | #include <sys/socket.h> |
---|
41 | #include <net/if_dl.h> |
---|
42 | #include <bsp/fdt.h> |
---|
43 | #include "../../../../../../rtemsbsd/sys/powerpc/drivers/net/ethernet/freescale/dpaa/if_fmanmac.h" |
---|
44 | #endif /* __rtems__ */ |
---|
45 | #include <linux/init.h> |
---|
46 | #include <linux/module.h> |
---|
47 | #include <linux/of_address.h> |
---|
48 | #include <linux/of_platform.h> |
---|
49 | #include <linux/of_net.h> |
---|
50 | #include <linux/of_mdio.h> |
---|
51 | #include <linux/device.h> |
---|
52 | #include <linux/phy.h> |
---|
53 | #include <linux/netdevice.h> |
---|
54 | #include <linux/phy_fixed.h> |
---|
55 | #include <linux/etherdevice.h> |
---|
56 | #include <linux/libfdt_env.h> |
---|
57 | |
---|
58 | #include "mac.h" |
---|
59 | #include "fman_mac.h" |
---|
60 | #include "fman_dtsec.h" |
---|
61 | #include "fman_tgec.h" |
---|
62 | #include "fman_memac.h" |
---|
63 | |
---|
64 | MODULE_LICENSE("Dual BSD/GPL"); |
---|
65 | MODULE_DESCRIPTION("FSL FMan MAC API based driver"); |
---|
66 | |
---|
67 | struct mac_priv_s { |
---|
68 | struct device *dev; |
---|
69 | void __iomem *vaddr; |
---|
70 | u8 cell_index; |
---|
71 | phy_interface_t phy_if; |
---|
72 | struct fman *fman; |
---|
73 | struct device_node *phy_node; |
---|
74 | struct device_node *internal_phy_node; |
---|
75 | #ifdef __rtems__ |
---|
76 | struct device_node phy_node_storage; |
---|
77 | struct device_node internal_phy_node_storage; |
---|
78 | #endif /* __rtems__ */ |
---|
79 | /* List of multicast addresses */ |
---|
80 | struct list_head mc_addr_list; |
---|
81 | struct platform_device *eth_dev; |
---|
82 | struct fixed_phy_status *fixed_link; |
---|
83 | u16 speed; |
---|
84 | u16 max_speed; |
---|
85 | |
---|
86 | int (*enable)(struct fman_mac *mac_dev, enum comm_mode mode); |
---|
87 | int (*disable)(struct fman_mac *mac_dev, enum comm_mode mode); |
---|
88 | }; |
---|
89 | |
---|
90 | struct mac_address { |
---|
91 | u8 addr[ETH_ALEN]; |
---|
92 | struct list_head list; |
---|
93 | }; |
---|
94 | |
---|
95 | static void mac_exception(void *handle, enum fman_mac_exceptions ex) |
---|
96 | { |
---|
97 | struct mac_device *mac_dev; |
---|
98 | struct mac_priv_s *priv; |
---|
99 | |
---|
100 | mac_dev = handle; |
---|
101 | priv = mac_dev->priv; |
---|
102 | |
---|
103 | if (ex == FM_MAC_EX_10G_RX_FIFO_OVFL) { |
---|
104 | /* don't flag RX FIFO after the first */ |
---|
105 | mac_dev->set_exception(mac_dev->fman_mac, |
---|
106 | FM_MAC_EX_10G_RX_FIFO_OVFL, false); |
---|
107 | dev_err(priv->dev, "10G MAC got RX FIFO Error = %x\n", ex); |
---|
108 | } |
---|
109 | |
---|
110 | #ifndef __rtems__ |
---|
111 | dev_dbg(priv->dev, "%s:%s() -> %d\n", KBUILD_BASENAME ".c", |
---|
112 | __func__, ex); |
---|
113 | #endif /* __rtems__ */ |
---|
114 | } |
---|
115 | |
---|
116 | static void set_fman_mac_params(struct mac_device *mac_dev, |
---|
117 | struct fman_mac_params *params) |
---|
118 | { |
---|
119 | struct mac_priv_s *priv = mac_dev->priv; |
---|
120 | |
---|
121 | #ifndef __rtems__ |
---|
122 | params->base_addr = (typeof(params->base_addr)) |
---|
123 | devm_ioremap(priv->dev, mac_dev->res->start, |
---|
124 | resource_size(mac_dev->res)); |
---|
125 | #else /* __rtems__ */ |
---|
126 | params->base_addr = priv->vaddr; |
---|
127 | #endif /* __rtems__ */ |
---|
128 | memcpy(¶ms->addr, mac_dev->addr, sizeof(mac_dev->addr)); |
---|
129 | params->max_speed = priv->max_speed; |
---|
130 | params->phy_if = priv->phy_if; |
---|
131 | params->basex_if = false; |
---|
132 | params->mac_id = priv->cell_index; |
---|
133 | params->fm = (void *)priv->fman; |
---|
134 | params->exception_cb = mac_exception; |
---|
135 | params->event_cb = mac_exception; |
---|
136 | params->dev_id = mac_dev; |
---|
137 | params->internal_phy_node = priv->internal_phy_node; |
---|
138 | } |
---|
139 | |
---|
140 | static int tgec_initialization(struct mac_device *mac_dev) |
---|
141 | { |
---|
142 | int err; |
---|
143 | struct mac_priv_s *priv; |
---|
144 | struct fman_mac_params params; |
---|
145 | u32 version; |
---|
146 | |
---|
147 | priv = mac_dev->priv; |
---|
148 | |
---|
149 | set_fman_mac_params(mac_dev, ¶ms); |
---|
150 | |
---|
151 | mac_dev->fman_mac = tgec_config(¶ms); |
---|
152 | if (!mac_dev->fman_mac) { |
---|
153 | err = -EINVAL; |
---|
154 | goto _return; |
---|
155 | } |
---|
156 | |
---|
157 | err = tgec_cfg_max_frame_len(mac_dev->fman_mac, fman_get_max_frm()); |
---|
158 | if (err < 0) |
---|
159 | goto _return_fm_mac_free; |
---|
160 | |
---|
161 | err = tgec_init(mac_dev->fman_mac); |
---|
162 | if (err < 0) |
---|
163 | goto _return_fm_mac_free; |
---|
164 | |
---|
165 | /* For 10G MAC, disable Tx ECC exception */ |
---|
166 | err = mac_dev->set_exception(mac_dev->fman_mac, |
---|
167 | FM_MAC_EX_10G_TX_ECC_ER, false); |
---|
168 | if (err < 0) |
---|
169 | goto _return_fm_mac_free; |
---|
170 | |
---|
171 | err = tgec_get_version(mac_dev->fman_mac, &version); |
---|
172 | if (err < 0) |
---|
173 | goto _return_fm_mac_free; |
---|
174 | |
---|
175 | dev_info(priv->dev, "FMan XGEC version: 0x%08x\n", version); |
---|
176 | |
---|
177 | goto _return; |
---|
178 | |
---|
179 | _return_fm_mac_free: |
---|
180 | tgec_free(mac_dev->fman_mac); |
---|
181 | |
---|
182 | _return: |
---|
183 | return err; |
---|
184 | } |
---|
185 | |
---|
186 | static int dtsec_initialization(struct mac_device *mac_dev) |
---|
187 | { |
---|
188 | int err; |
---|
189 | struct mac_priv_s *priv; |
---|
190 | struct fman_mac_params params; |
---|
191 | u32 version; |
---|
192 | |
---|
193 | priv = mac_dev->priv; |
---|
194 | |
---|
195 | set_fman_mac_params(mac_dev, ¶ms); |
---|
196 | |
---|
197 | mac_dev->fman_mac = dtsec_config(¶ms); |
---|
198 | if (!mac_dev->fman_mac) { |
---|
199 | err = -EINVAL; |
---|
200 | goto _return; |
---|
201 | } |
---|
202 | |
---|
203 | err = dtsec_cfg_max_frame_len(mac_dev->fman_mac, fman_get_max_frm()); |
---|
204 | if (err < 0) |
---|
205 | goto _return_fm_mac_free; |
---|
206 | |
---|
207 | err = dtsec_cfg_pad_and_crc(mac_dev->fman_mac, true); |
---|
208 | if (err < 0) |
---|
209 | goto _return_fm_mac_free; |
---|
210 | |
---|
211 | err = dtsec_init(mac_dev->fman_mac); |
---|
212 | if (err < 0) |
---|
213 | goto _return_fm_mac_free; |
---|
214 | |
---|
215 | /* For 1G MAC, disable by default the MIB counters overflow interrupt */ |
---|
216 | err = mac_dev->set_exception(mac_dev->fman_mac, |
---|
217 | FM_MAC_EX_1G_RX_MIB_CNT_OVFL, false); |
---|
218 | if (err < 0) |
---|
219 | goto _return_fm_mac_free; |
---|
220 | |
---|
221 | err = dtsec_get_version(mac_dev->fman_mac, &version); |
---|
222 | if (err < 0) |
---|
223 | goto _return_fm_mac_free; |
---|
224 | |
---|
225 | dev_info(priv->dev, "FMan dTSEC version: 0x%08x\n", version); |
---|
226 | |
---|
227 | goto _return; |
---|
228 | |
---|
229 | _return_fm_mac_free: |
---|
230 | dtsec_free(mac_dev->fman_mac); |
---|
231 | |
---|
232 | _return: |
---|
233 | return err; |
---|
234 | } |
---|
235 | |
---|
236 | static int memac_initialization(struct mac_device *mac_dev) |
---|
237 | { |
---|
238 | int err; |
---|
239 | struct mac_priv_s *priv; |
---|
240 | struct fman_mac_params params; |
---|
241 | |
---|
242 | priv = mac_dev->priv; |
---|
243 | |
---|
244 | set_fman_mac_params(mac_dev, ¶ms); |
---|
245 | |
---|
246 | if (priv->max_speed == SPEED_10000) |
---|
247 | params.phy_if = PHY_INTERFACE_MODE_XGMII; |
---|
248 | |
---|
249 | mac_dev->fman_mac = memac_config(¶ms); |
---|
250 | if (!mac_dev->fman_mac) { |
---|
251 | err = -EINVAL; |
---|
252 | goto _return; |
---|
253 | } |
---|
254 | |
---|
255 | err = memac_cfg_max_frame_len(mac_dev->fman_mac, fman_get_max_frm()); |
---|
256 | if (err < 0) |
---|
257 | goto _return_fm_mac_free; |
---|
258 | |
---|
259 | err = memac_cfg_reset_on_init(mac_dev->fman_mac, true); |
---|
260 | if (err < 0) |
---|
261 | goto _return_fm_mac_free; |
---|
262 | |
---|
263 | #ifndef __rtems__ |
---|
264 | err = memac_cfg_fixed_link(mac_dev->fman_mac, priv->fixed_link); |
---|
265 | if (err < 0) |
---|
266 | goto _return_fm_mac_free; |
---|
267 | #endif /* __rtems__ */ |
---|
268 | |
---|
269 | err = memac_init(mac_dev->fman_mac); |
---|
270 | if (err < 0) |
---|
271 | goto _return_fm_mac_free; |
---|
272 | |
---|
273 | dev_info(priv->dev, "FMan MEMAC\n"); |
---|
274 | |
---|
275 | goto _return; |
---|
276 | |
---|
277 | _return_fm_mac_free: |
---|
278 | memac_free(mac_dev->fman_mac); |
---|
279 | |
---|
280 | _return: |
---|
281 | return err; |
---|
282 | } |
---|
283 | |
---|
284 | static int start(struct mac_device *mac_dev) |
---|
285 | { |
---|
286 | int err; |
---|
287 | #ifndef __rtems__ |
---|
288 | struct phy_device *phy_dev = mac_dev->phy_dev; |
---|
289 | #endif /* __rtems__ */ |
---|
290 | struct mac_priv_s *priv = mac_dev->priv; |
---|
291 | |
---|
292 | err = priv->enable(mac_dev->fman_mac, COMM_MODE_RX_AND_TX); |
---|
293 | #ifndef __rtems__ |
---|
294 | if (!err && phy_dev) |
---|
295 | phy_start(phy_dev); |
---|
296 | #endif /* __rtems__ */ |
---|
297 | |
---|
298 | return err; |
---|
299 | } |
---|
300 | |
---|
301 | static int stop(struct mac_device *mac_dev) |
---|
302 | { |
---|
303 | struct mac_priv_s *priv = mac_dev->priv; |
---|
304 | |
---|
305 | #ifndef __rtems__ |
---|
306 | if (mac_dev->phy_dev) |
---|
307 | phy_stop(mac_dev->phy_dev); |
---|
308 | #endif /* __rtems__ */ |
---|
309 | |
---|
310 | return priv->disable(mac_dev->fman_mac, COMM_MODE_RX_AND_TX); |
---|
311 | } |
---|
312 | |
---|
313 | static int set_multi(struct net_device *net_dev, struct mac_device *mac_dev) |
---|
314 | { |
---|
315 | struct mac_priv_s *priv; |
---|
316 | struct mac_address *old_addr, *tmp; |
---|
317 | #ifndef __rtems__ |
---|
318 | struct netdev_hw_addr *ha; |
---|
319 | #endif /* __rtems__ */ |
---|
320 | int err; |
---|
321 | enet_addr_t *addr; |
---|
322 | #ifdef __rtems__ |
---|
323 | struct ifnet *ifp; |
---|
324 | struct ifmultiaddr *ifma; |
---|
325 | #endif /* __rtems__ */ |
---|
326 | |
---|
327 | priv = mac_dev->priv; |
---|
328 | |
---|
329 | /* Clear previous address list */ |
---|
330 | list_for_each_entry_safe(old_addr, tmp, &priv->mc_addr_list, list) { |
---|
331 | addr = (enet_addr_t *)old_addr->addr; |
---|
332 | err = mac_dev->remove_hash_mac_addr(mac_dev->fman_mac, addr); |
---|
333 | if (err < 0) |
---|
334 | return err; |
---|
335 | |
---|
336 | list_del(&old_addr->list); |
---|
337 | kfree(old_addr); |
---|
338 | } |
---|
339 | |
---|
340 | /* Add all the addresses from the new list */ |
---|
341 | #ifndef __rtems__ |
---|
342 | netdev_for_each_mc_addr(ha, net_dev) { |
---|
343 | addr = (enet_addr_t *)ha->addr; |
---|
344 | #else /* __rtems__ */ |
---|
345 | ifp = mac_dev->net_dev.ifp; |
---|
346 | if_maddr_rlock(ifp); |
---|
347 | TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { |
---|
348 | if (ifma->ifma_addr->sa_family != AF_LINK) |
---|
349 | continue; |
---|
350 | addr = (enet_addr_t *)LLADDR((struct sockaddr_dl *)ifma->ifma_addr); |
---|
351 | #endif /* __rtems__ */ |
---|
352 | err = mac_dev->add_hash_mac_addr(mac_dev->fman_mac, addr); |
---|
353 | if (err < 0) |
---|
354 | return err; |
---|
355 | |
---|
356 | tmp = kmalloc(sizeof(*tmp), GFP_ATOMIC); |
---|
357 | if (!tmp) |
---|
358 | return -ENOMEM; |
---|
359 | |
---|
360 | ether_addr_copy(tmp->addr, *addr); |
---|
361 | list_add(&tmp->list, &priv->mc_addr_list); |
---|
362 | } |
---|
363 | #ifdef __rtems__ |
---|
364 | if_maddr_runlock(ifp); |
---|
365 | #endif /* __rtems__ */ |
---|
366 | return 0; |
---|
367 | } |
---|
368 | |
---|
369 | /** |
---|
370 | * fman_set_mac_active_pause |
---|
371 | * @mac_dev: A pointer to the MAC device |
---|
372 | * @rx: Pause frame setting for RX |
---|
373 | * @tx: Pause frame setting for TX |
---|
374 | * |
---|
375 | * Set the MAC RX/TX PAUSE frames settings |
---|
376 | * |
---|
377 | * Avoid redundant calls to FMD, if the MAC driver already contains the desired |
---|
378 | * active PAUSE settings. Otherwise, the new active settings should be reflected |
---|
379 | * in FMan. |
---|
380 | * |
---|
381 | * Return: 0 on success; Error code otherwise. |
---|
382 | */ |
---|
383 | int fman_set_mac_active_pause(struct mac_device *mac_dev, bool rx, bool tx) |
---|
384 | { |
---|
385 | struct fman_mac *fman_mac = mac_dev->fman_mac; |
---|
386 | int err = 0; |
---|
387 | |
---|
388 | if (rx != mac_dev->rx_pause_active) { |
---|
389 | err = mac_dev->set_rx_pause(fman_mac, rx); |
---|
390 | if (likely(err == 0)) |
---|
391 | mac_dev->rx_pause_active = rx; |
---|
392 | } |
---|
393 | |
---|
394 | if (tx != mac_dev->tx_pause_active) { |
---|
395 | u16 pause_time = (tx ? FSL_FM_PAUSE_TIME_ENABLE : |
---|
396 | FSL_FM_PAUSE_TIME_DISABLE); |
---|
397 | |
---|
398 | err = mac_dev->set_tx_pause(fman_mac, 0, pause_time, 0); |
---|
399 | |
---|
400 | if (likely(err == 0)) |
---|
401 | mac_dev->tx_pause_active = tx; |
---|
402 | } |
---|
403 | |
---|
404 | return err; |
---|
405 | } |
---|
406 | EXPORT_SYMBOL(fman_set_mac_active_pause); |
---|
407 | |
---|
408 | #ifndef __rtems__ |
---|
409 | /** |
---|
410 | * fman_get_pause_cfg |
---|
411 | * @mac_dev: A pointer to the MAC device |
---|
412 | * @rx: Return value for RX setting |
---|
413 | * @tx: Return value for TX setting |
---|
414 | * |
---|
415 | * Determine the MAC RX/TX PAUSE frames settings based on PHY |
---|
416 | * autonegotiation or values set by eththool. |
---|
417 | * |
---|
418 | * Return: Pointer to FMan device. |
---|
419 | */ |
---|
420 | void fman_get_pause_cfg(struct mac_device *mac_dev, bool *rx_pause, |
---|
421 | bool *tx_pause) |
---|
422 | { |
---|
423 | struct phy_device *phy_dev = mac_dev->phy_dev; |
---|
424 | u16 lcl_adv, rmt_adv; |
---|
425 | u8 flowctrl; |
---|
426 | |
---|
427 | *rx_pause = *tx_pause = false; |
---|
428 | |
---|
429 | if (!phy_dev->duplex) |
---|
430 | return; |
---|
431 | |
---|
432 | /* If PAUSE autonegotiation is disabled, the TX/RX PAUSE settings |
---|
433 | * are those set by ethtool. |
---|
434 | */ |
---|
435 | if (!mac_dev->autoneg_pause) { |
---|
436 | *rx_pause = mac_dev->rx_pause_req; |
---|
437 | *tx_pause = mac_dev->tx_pause_req; |
---|
438 | return; |
---|
439 | } |
---|
440 | |
---|
441 | /* Else if PAUSE autonegotiation is enabled, the TX/RX PAUSE |
---|
442 | * settings depend on the result of the link negotiation. |
---|
443 | */ |
---|
444 | |
---|
445 | /* get local capabilities */ |
---|
446 | lcl_adv = 0; |
---|
447 | if (phy_dev->advertising & ADVERTISED_Pause) |
---|
448 | lcl_adv |= ADVERTISE_PAUSE_CAP; |
---|
449 | if (phy_dev->advertising & ADVERTISED_Asym_Pause) |
---|
450 | lcl_adv |= ADVERTISE_PAUSE_ASYM; |
---|
451 | |
---|
452 | /* get link partner capabilities */ |
---|
453 | rmt_adv = 0; |
---|
454 | if (phy_dev->pause) |
---|
455 | rmt_adv |= LPA_PAUSE_CAP; |
---|
456 | if (phy_dev->asym_pause) |
---|
457 | rmt_adv |= LPA_PAUSE_ASYM; |
---|
458 | |
---|
459 | /* Calculate TX/RX settings based on local and peer advertised |
---|
460 | * symmetric/asymmetric PAUSE capabilities. |
---|
461 | */ |
---|
462 | flowctrl = mii_resolve_flowctrl_fdx(lcl_adv, rmt_adv); |
---|
463 | if (flowctrl & FLOW_CTRL_RX) |
---|
464 | *rx_pause = true; |
---|
465 | if (flowctrl & FLOW_CTRL_TX) |
---|
466 | *tx_pause = true; |
---|
467 | } |
---|
468 | EXPORT_SYMBOL(fman_get_pause_cfg); |
---|
469 | |
---|
470 | static void adjust_link_void(struct net_device *net_dev) |
---|
471 | { |
---|
472 | } |
---|
473 | |
---|
474 | static void adjust_link_dtsec(struct net_device *net_dev) |
---|
475 | { |
---|
476 | struct device *dev = net_dev->dev.parent; |
---|
477 | struct dpaa_eth_data *eth_data = dev->platform_data; |
---|
478 | struct mac_device *mac_dev = eth_data->mac_dev; |
---|
479 | struct phy_device *phy_dev = mac_dev->phy_dev; |
---|
480 | struct fman_mac *fman_mac; |
---|
481 | bool rx_pause, tx_pause; |
---|
482 | int err; |
---|
483 | |
---|
484 | fman_mac = mac_dev->fman_mac; |
---|
485 | if (!phy_dev->link) { |
---|
486 | dtsec_restart_autoneg(fman_mac); |
---|
487 | |
---|
488 | return; |
---|
489 | } |
---|
490 | |
---|
491 | dtsec_adjust_link(fman_mac, phy_dev->speed); |
---|
492 | fman_get_pause_cfg(mac_dev, &rx_pause, &tx_pause); |
---|
493 | err = fman_set_mac_active_pause(mac_dev, rx_pause, tx_pause); |
---|
494 | if (err < 0) |
---|
495 | netdev_err(net_dev, "fman_set_mac_active_pause() = %d\n", err); |
---|
496 | } |
---|
497 | |
---|
498 | static void adjust_link_memac(struct net_device *net_dev) |
---|
499 | { |
---|
500 | struct device *dev = net_dev->dev.parent; |
---|
501 | struct dpaa_eth_data *eth_data = dev->platform_data; |
---|
502 | struct mac_device *mac_dev = eth_data->mac_dev; |
---|
503 | struct phy_device *phy_dev = mac_dev->phy_dev; |
---|
504 | struct fman_mac *fman_mac; |
---|
505 | bool rx_pause, tx_pause; |
---|
506 | int err; |
---|
507 | |
---|
508 | fman_mac = mac_dev->fman_mac; |
---|
509 | memac_adjust_link(fman_mac, phy_dev->speed); |
---|
510 | |
---|
511 | fman_get_pause_cfg(mac_dev, &rx_pause, &tx_pause); |
---|
512 | err = fman_set_mac_active_pause(mac_dev, rx_pause, tx_pause); |
---|
513 | if (err < 0) |
---|
514 | netdev_err(net_dev, "fman_set_mac_active_pause() = %d\n", err); |
---|
515 | } |
---|
516 | |
---|
517 | /* Initializes driver's PHY state, and attaches to the PHY. |
---|
518 | * Returns 0 on success. |
---|
519 | */ |
---|
520 | static struct phy_device *init_phy(struct net_device *net_dev, |
---|
521 | struct mac_device *mac_dev, |
---|
522 | void (*adj_lnk)(struct net_device *)) |
---|
523 | { |
---|
524 | struct phy_device *phy_dev; |
---|
525 | struct mac_priv_s *priv = mac_dev->priv; |
---|
526 | |
---|
527 | phy_dev = of_phy_connect(net_dev, priv->phy_node, adj_lnk, 0, |
---|
528 | priv->phy_if); |
---|
529 | if (!phy_dev) { |
---|
530 | netdev_err(net_dev, "Could not connect to PHY\n"); |
---|
531 | return NULL; |
---|
532 | } |
---|
533 | |
---|
534 | /* Remove any features not supported by the controller */ |
---|
535 | phy_dev->supported &= mac_dev->if_support; |
---|
536 | /* Enable the symmetric and asymmetric PAUSE frame advertisements, |
---|
537 | * as most of the PHY drivers do not enable them by default. |
---|
538 | */ |
---|
539 | phy_dev->supported |= (SUPPORTED_Pause | SUPPORTED_Asym_Pause); |
---|
540 | phy_dev->advertising = phy_dev->supported; |
---|
541 | |
---|
542 | mac_dev->phy_dev = phy_dev; |
---|
543 | |
---|
544 | return phy_dev; |
---|
545 | } |
---|
546 | |
---|
547 | static struct phy_device *dtsec_init_phy(struct net_device *net_dev, |
---|
548 | struct mac_device *mac_dev) |
---|
549 | { |
---|
550 | return init_phy(net_dev, mac_dev, &adjust_link_dtsec); |
---|
551 | } |
---|
552 | |
---|
553 | static struct phy_device *tgec_init_phy(struct net_device *net_dev, |
---|
554 | struct mac_device *mac_dev) |
---|
555 | { |
---|
556 | return init_phy(net_dev, mac_dev, adjust_link_void); |
---|
557 | } |
---|
558 | |
---|
559 | static struct phy_device *memac_init_phy(struct net_device *net_dev, |
---|
560 | struct mac_device *mac_dev) |
---|
561 | { |
---|
562 | return init_phy(net_dev, mac_dev, &adjust_link_memac); |
---|
563 | } |
---|
564 | #else /* __rtems__ */ |
---|
565 | static void dtsec_do_adjust_link(struct mac_device *mac_dev, u16 speed) |
---|
566 | { |
---|
567 | dtsec_adjust_link(mac_dev->fman_mac, speed); |
---|
568 | } |
---|
569 | |
---|
570 | static void tgec_do_adjust_link(struct mac_device *mac_dev, u16 speed) |
---|
571 | { |
---|
572 | /* VOID */ |
---|
573 | } |
---|
574 | |
---|
575 | static void memac_do_adjust_link(struct mac_device *mac_dev, u16 speed) |
---|
576 | { |
---|
577 | memac_adjust_link(mac_dev->fman_mac, speed); |
---|
578 | } |
---|
579 | #endif /* __rtems__ */ |
---|
580 | |
---|
581 | static void setup_dtsec(struct mac_device *mac_dev) |
---|
582 | { |
---|
583 | #ifndef __rtems__ |
---|
584 | mac_dev->init_phy = dtsec_init_phy; |
---|
585 | #else /* __rtems__ */ |
---|
586 | mac_dev->adjust_link = dtsec_do_adjust_link; |
---|
587 | #endif /* __rtems__ */ |
---|
588 | mac_dev->init = dtsec_initialization; |
---|
589 | mac_dev->set_promisc = dtsec_set_promiscuous; |
---|
590 | mac_dev->change_addr = dtsec_modify_mac_address; |
---|
591 | mac_dev->add_hash_mac_addr = dtsec_add_hash_mac_address; |
---|
592 | mac_dev->remove_hash_mac_addr = dtsec_del_hash_mac_address; |
---|
593 | mac_dev->set_tx_pause = dtsec_set_tx_pause_frames; |
---|
594 | mac_dev->set_rx_pause = dtsec_accept_rx_pause_frames; |
---|
595 | mac_dev->set_exception = dtsec_set_exception; |
---|
596 | mac_dev->set_multi = set_multi; |
---|
597 | mac_dev->start = start; |
---|
598 | mac_dev->stop = stop; |
---|
599 | |
---|
600 | mac_dev->priv->enable = dtsec_enable; |
---|
601 | mac_dev->priv->disable = dtsec_disable; |
---|
602 | } |
---|
603 | |
---|
604 | static void setup_tgec(struct mac_device *mac_dev) |
---|
605 | { |
---|
606 | #ifndef __rtems__ |
---|
607 | mac_dev->init_phy = tgec_init_phy; |
---|
608 | #else /* __rtems__ */ |
---|
609 | mac_dev->adjust_link = tgec_do_adjust_link; |
---|
610 | #endif /* __rtems__ */ |
---|
611 | mac_dev->init = tgec_initialization; |
---|
612 | mac_dev->set_promisc = tgec_set_promiscuous; |
---|
613 | mac_dev->change_addr = tgec_modify_mac_address; |
---|
614 | mac_dev->add_hash_mac_addr = tgec_add_hash_mac_address; |
---|
615 | mac_dev->remove_hash_mac_addr = tgec_del_hash_mac_address; |
---|
616 | mac_dev->set_tx_pause = tgec_set_tx_pause_frames; |
---|
617 | mac_dev->set_rx_pause = tgec_accept_rx_pause_frames; |
---|
618 | mac_dev->set_exception = tgec_set_exception; |
---|
619 | mac_dev->set_multi = set_multi; |
---|
620 | mac_dev->start = start; |
---|
621 | mac_dev->stop = stop; |
---|
622 | |
---|
623 | mac_dev->priv->enable = tgec_enable; |
---|
624 | mac_dev->priv->disable = tgec_disable; |
---|
625 | } |
---|
626 | |
---|
627 | static void setup_memac(struct mac_device *mac_dev) |
---|
628 | { |
---|
629 | #ifndef __rtems__ |
---|
630 | mac_dev->init_phy = memac_init_phy; |
---|
631 | #else /* __rtems__ */ |
---|
632 | mac_dev->adjust_link = memac_do_adjust_link; |
---|
633 | #endif /* __rtems__ */ |
---|
634 | mac_dev->init = memac_initialization; |
---|
635 | mac_dev->set_promisc = memac_set_promiscuous; |
---|
636 | mac_dev->change_addr = memac_modify_mac_address; |
---|
637 | mac_dev->add_hash_mac_addr = memac_add_hash_mac_address; |
---|
638 | mac_dev->remove_hash_mac_addr = memac_del_hash_mac_address; |
---|
639 | mac_dev->set_tx_pause = memac_set_tx_pause_frames; |
---|
640 | mac_dev->set_rx_pause = memac_accept_rx_pause_frames; |
---|
641 | mac_dev->set_exception = memac_set_exception; |
---|
642 | mac_dev->set_multi = set_multi; |
---|
643 | mac_dev->start = start; |
---|
644 | mac_dev->stop = stop; |
---|
645 | |
---|
646 | mac_dev->priv->enable = memac_enable; |
---|
647 | mac_dev->priv->disable = memac_disable; |
---|
648 | } |
---|
649 | |
---|
650 | #define DTSEC_SUPPORTED \ |
---|
651 | (SUPPORTED_10baseT_Half \ |
---|
652 | | SUPPORTED_10baseT_Full \ |
---|
653 | | SUPPORTED_100baseT_Half \ |
---|
654 | | SUPPORTED_100baseT_Full \ |
---|
655 | | SUPPORTED_Autoneg \ |
---|
656 | | SUPPORTED_Pause \ |
---|
657 | | SUPPORTED_Asym_Pause \ |
---|
658 | | SUPPORTED_MII) |
---|
659 | |
---|
660 | #ifndef __rtems__ |
---|
661 | static DEFINE_MUTEX(eth_lock); |
---|
662 | #endif /* __rtems__ */ |
---|
663 | |
---|
664 | static const u16 phy2speed[] = { |
---|
665 | [PHY_INTERFACE_MODE_MII] = SPEED_100, |
---|
666 | [PHY_INTERFACE_MODE_GMII] = SPEED_1000, |
---|
667 | [PHY_INTERFACE_MODE_SGMII] = SPEED_1000, |
---|
668 | [PHY_INTERFACE_MODE_TBI] = SPEED_1000, |
---|
669 | [PHY_INTERFACE_MODE_RMII] = SPEED_100, |
---|
670 | [PHY_INTERFACE_MODE_RGMII] = SPEED_1000, |
---|
671 | [PHY_INTERFACE_MODE_RGMII_ID] = SPEED_1000, |
---|
672 | [PHY_INTERFACE_MODE_RGMII_RXID] = SPEED_1000, |
---|
673 | [PHY_INTERFACE_MODE_RGMII_TXID] = SPEED_1000, |
---|
674 | [PHY_INTERFACE_MODE_RTBI] = SPEED_1000, |
---|
675 | [PHY_INTERFACE_MODE_QSGMII] = SPEED_1000, |
---|
676 | [PHY_INTERFACE_MODE_XGMII] = SPEED_10000 |
---|
677 | }; |
---|
678 | |
---|
679 | static struct platform_device *dpaa_eth_add_device(int fman_id, |
---|
680 | struct mac_device *mac_dev, |
---|
681 | struct device_node *node) |
---|
682 | { |
---|
683 | struct platform_device *pdev; |
---|
684 | struct dpaa_eth_data data; |
---|
685 | struct mac_priv_s *priv; |
---|
686 | #ifndef __rtems__ |
---|
687 | static int dpaa_eth_dev_cnt; |
---|
688 | #endif /* __rtems__ */ |
---|
689 | int ret; |
---|
690 | |
---|
691 | priv = mac_dev->priv; |
---|
692 | |
---|
693 | data.mac_dev = mac_dev; |
---|
694 | data.mac_hw_id = priv->cell_index; |
---|
695 | data.fman_hw_id = fman_id; |
---|
696 | data.mac_node = node; |
---|
697 | |
---|
698 | #ifndef __rtems__ |
---|
699 | mutex_lock(ð_lock); |
---|
700 | |
---|
701 | pdev = platform_device_alloc("dpaa-ethernet", dpaa_eth_dev_cnt); |
---|
702 | if (!pdev) { |
---|
703 | ret = -ENOMEM; |
---|
704 | goto no_mem; |
---|
705 | } |
---|
706 | |
---|
707 | set_dma_ops(&pdev->dev, get_dma_ops(priv->dev)); |
---|
708 | |
---|
709 | ret = platform_device_add_data(pdev, &data, sizeof(data)); |
---|
710 | if (ret) |
---|
711 | goto err; |
---|
712 | |
---|
713 | ret = platform_device_add(pdev); |
---|
714 | if (ret) |
---|
715 | goto err; |
---|
716 | |
---|
717 | dpaa_eth_dev_cnt++; |
---|
718 | mutex_unlock(ð_lock); |
---|
719 | |
---|
720 | return pdev; |
---|
721 | |
---|
722 | err: |
---|
723 | platform_device_put(pdev); |
---|
724 | no_mem: |
---|
725 | mutex_unlock(ð_lock); |
---|
726 | |
---|
727 | return ERR_PTR(ret); |
---|
728 | #else /* __rtems__ */ |
---|
729 | pdev = &mac_dev->pdev; |
---|
730 | mac_dev->data = data; |
---|
731 | pdev->platform_data = &mac_dev->data; |
---|
732 | ret = dpaa_eth_priv_probe(pdev, mac_dev); |
---|
733 | BSD_ASSERT(ret == 0); |
---|
734 | return pdev; |
---|
735 | #endif /* __rtems__ */ |
---|
736 | } |
---|
737 | |
---|
738 | #ifndef __rtems__ |
---|
739 | static const struct of_device_id mac_match[] = { |
---|
740 | { .compatible = "fsl,fman-dtsec" }, |
---|
741 | { .compatible = "fsl,fman-xgec" }, |
---|
742 | { .compatible = "fsl,fman-memac" }, |
---|
743 | {} |
---|
744 | }; |
---|
745 | MODULE_DEVICE_TABLE(of, mac_match); |
---|
746 | #endif /* __rtems__ */ |
---|
747 | |
---|
748 | #ifndef __rtems__ |
---|
749 | static int mac_probe(struct platform_device *_of_dev) |
---|
750 | #else /* __rtems__ */ |
---|
751 | static int mac_probe(device_t _dev, struct platform_device *_of_dev, struct fman *fman) |
---|
752 | #endif /* __rtems__ */ |
---|
753 | { |
---|
754 | #ifdef __rtems__ |
---|
755 | struct fman_mac_softc *sc = device_get_softc(_dev); |
---|
756 | #endif /* __rtems__ */ |
---|
757 | int err, i, nph; |
---|
758 | struct device *dev; |
---|
759 | struct device_node *mac_node, *dev_node; |
---|
760 | struct mac_device *mac_dev; |
---|
761 | #ifndef __rtems__ |
---|
762 | struct platform_device *of_dev; |
---|
763 | #endif /* __rtems__ */ |
---|
764 | struct resource res; |
---|
765 | struct mac_priv_s *priv; |
---|
766 | const u8 *mac_addr; |
---|
767 | u32 val; |
---|
768 | u8 fman_id; |
---|
769 | int phy_if; |
---|
770 | |
---|
771 | dev = &_of_dev->dev; |
---|
772 | mac_node = dev->of_node; |
---|
773 | |
---|
774 | #ifndef __rtems__ |
---|
775 | mac_dev = devm_kzalloc(dev, sizeof(*mac_dev), GFP_KERNEL); |
---|
776 | if (!mac_dev) { |
---|
777 | err = -ENOMEM; |
---|
778 | dev_err(dev, "devm_kzalloc() = %d\n", err); |
---|
779 | goto _return; |
---|
780 | } |
---|
781 | #else /* __rtems__ */ |
---|
782 | mac_dev = &sc->mac_dev; |
---|
783 | #endif /* __rtems__ */ |
---|
784 | priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); |
---|
785 | if (!priv) { |
---|
786 | err = -ENOMEM; |
---|
787 | goto _return; |
---|
788 | } |
---|
789 | |
---|
790 | /* Save private information */ |
---|
791 | mac_dev->priv = priv; |
---|
792 | priv->dev = dev; |
---|
793 | |
---|
794 | if (of_device_is_compatible(mac_node, "fsl,fman-dtsec")) { |
---|
795 | setup_dtsec(mac_dev); |
---|
796 | #ifndef __rtems__ |
---|
797 | priv->internal_phy_node = of_parse_phandle(mac_node, |
---|
798 | "tbi-handle", 0); |
---|
799 | #else /* __rtems__ */ |
---|
800 | priv->internal_phy_node = of_parse_phandle( |
---|
801 | &priv->internal_phy_node_storage, mac_node, "tbi-handle", |
---|
802 | 0); |
---|
803 | #endif /* __rtems__ */ |
---|
804 | } else if (of_device_is_compatible(mac_node, "fsl,fman-xgec")) { |
---|
805 | setup_tgec(mac_dev); |
---|
806 | } else if (of_device_is_compatible(mac_node, "fsl,fman-memac")) { |
---|
807 | setup_memac(mac_dev); |
---|
808 | #ifndef __rtems__ |
---|
809 | priv->internal_phy_node = of_parse_phandle(mac_node, |
---|
810 | "pcsphy-handle", 0); |
---|
811 | #else /* __rtems__ */ |
---|
812 | priv->internal_phy_node = of_parse_phandle( |
---|
813 | &priv->internal_phy_node_storage, mac_node, "pcsphy-handle", |
---|
814 | 0); |
---|
815 | #endif /* __rtems__ */ |
---|
816 | } else { |
---|
817 | #ifndef __rtems__ |
---|
818 | dev_err(dev, "MAC node (%s) contains unsupported MAC\n", |
---|
819 | mac_node->full_name); |
---|
820 | #endif /* __rtems__ */ |
---|
821 | err = -EINVAL; |
---|
822 | goto _return; |
---|
823 | } |
---|
824 | |
---|
825 | /* Register mac_dev */ |
---|
826 | dev_set_drvdata(dev, mac_dev); |
---|
827 | |
---|
828 | INIT_LIST_HEAD(&priv->mc_addr_list); |
---|
829 | |
---|
830 | /* Get the FM node */ |
---|
831 | #ifndef __rtems__ |
---|
832 | dev_node = of_get_parent(mac_node); |
---|
833 | if (!dev_node) { |
---|
834 | dev_err(dev, "of_get_parent(%s) failed\n", |
---|
835 | mac_node->full_name); |
---|
836 | err = -EINVAL; |
---|
837 | goto _return_dev_set_drvdata; |
---|
838 | } |
---|
839 | |
---|
840 | of_dev = of_find_device_by_node(dev_node); |
---|
841 | if (!of_dev) { |
---|
842 | dev_err(dev, "of_find_device_by_node(%s) failed\n", |
---|
843 | dev_node->full_name); |
---|
844 | err = -EINVAL; |
---|
845 | goto _return_of_node_put; |
---|
846 | } |
---|
847 | |
---|
848 | /* Get the FMan cell-index */ |
---|
849 | err = of_property_read_u32(dev_node, "cell-index", &val); |
---|
850 | if (err) { |
---|
851 | dev_err(dev, "failed to read cell-index for %s\n", |
---|
852 | dev_node->full_name); |
---|
853 | err = -EINVAL; |
---|
854 | goto _return_of_node_put; |
---|
855 | } |
---|
856 | /* cell-index 0 => FMan id 1 */ |
---|
857 | fman_id = (u8)(val + 1); |
---|
858 | |
---|
859 | priv->fman = fman_bind(&of_dev->dev); |
---|
860 | if (!priv->fman) { |
---|
861 | dev_err(dev, "fman_bind(%s) failed\n", dev_node->full_name); |
---|
862 | err = -ENODEV; |
---|
863 | goto _return_of_node_put; |
---|
864 | } |
---|
865 | |
---|
866 | of_node_put(dev_node); |
---|
867 | #else /* __rtems__ */ |
---|
868 | priv->fman = fman; |
---|
869 | fman_id = (u8)device_get_unit(_dev); |
---|
870 | #endif /* __rtems__ */ |
---|
871 | |
---|
872 | /* Get the address of the memory mapped registers */ |
---|
873 | err = of_address_to_resource(mac_node, 0, &res); |
---|
874 | if (err < 0) { |
---|
875 | dev_err(dev, "of_address_to_resource(%s) = %d\n", |
---|
876 | mac_node->full_name, err); |
---|
877 | goto _return_dev_set_drvdata; |
---|
878 | } |
---|
879 | |
---|
880 | #ifndef __rtems__ |
---|
881 | mac_dev->res = __devm_request_region(dev, |
---|
882 | fman_get_mem_region(priv->fman), |
---|
883 | res.start, res.end + 1 - res.start, |
---|
884 | "mac"); |
---|
885 | if (!mac_dev->res) { |
---|
886 | dev_err(dev, "__devm_request_mem_region(mac) failed\n"); |
---|
887 | err = -EBUSY; |
---|
888 | goto _return_dev_set_drvdata; |
---|
889 | } |
---|
890 | |
---|
891 | priv->vaddr = devm_ioremap(dev, mac_dev->res->start, |
---|
892 | mac_dev->res->end + 1 - mac_dev->res->start); |
---|
893 | if (!priv->vaddr) { |
---|
894 | dev_err(dev, "devm_ioremap() failed\n"); |
---|
895 | err = -EIO; |
---|
896 | goto _return_dev_set_drvdata; |
---|
897 | } |
---|
898 | #else /* __rtems__ */ |
---|
899 | priv->vaddr = devm_ioremap(dev, res.start, res.end + 1 - res.start); |
---|
900 | #endif /* __rtems__ */ |
---|
901 | |
---|
902 | if (!of_device_is_available(mac_node)) { |
---|
903 | #ifndef __rtems__ |
---|
904 | devm_iounmap(dev, priv->vaddr); |
---|
905 | __devm_release_region(dev, fman_get_mem_region(priv->fman), |
---|
906 | res.start, res.end + 1 - res.start); |
---|
907 | devm_kfree(dev, mac_dev); |
---|
908 | #endif /* __rtems__ */ |
---|
909 | dev_set_drvdata(dev, NULL); |
---|
910 | return -ENODEV; |
---|
911 | } |
---|
912 | |
---|
913 | /* Get the cell-index */ |
---|
914 | err = of_property_read_u32(mac_node, "cell-index", &val); |
---|
915 | if (err) { |
---|
916 | dev_err(dev, "failed to read cell-index for %s\n", |
---|
917 | mac_node->full_name); |
---|
918 | err = -EINVAL; |
---|
919 | goto _return_dev_set_drvdata; |
---|
920 | } |
---|
921 | priv->cell_index = (u8)val; |
---|
922 | |
---|
923 | /* Get the MAC address */ |
---|
924 | mac_addr = of_get_mac_address(mac_node); |
---|
925 | if (!mac_addr) { |
---|
926 | dev_err(dev, "of_get_mac_address(%s) failed\n", |
---|
927 | mac_node->full_name); |
---|
928 | err = -EINVAL; |
---|
929 | goto _return_dev_set_drvdata; |
---|
930 | } |
---|
931 | memcpy(mac_dev->addr, mac_addr, sizeof(mac_dev->addr)); |
---|
932 | |
---|
933 | /* Get the port handles */ |
---|
934 | nph = of_count_phandle_with_args(mac_node, "fsl,fman-ports", NULL); |
---|
935 | if (unlikely(nph < 0)) { |
---|
936 | dev_err(dev, "of_count_phandle_with_args(%s, fsl,fman-ports) failed\n", |
---|
937 | mac_node->full_name); |
---|
938 | err = nph; |
---|
939 | goto _return_dev_set_drvdata; |
---|
940 | } |
---|
941 | |
---|
942 | if (nph != ARRAY_SIZE(mac_dev->port)) { |
---|
943 | dev_err(dev, "Not supported number of fman-ports handles of mac node %s from device tree\n", |
---|
944 | mac_node->full_name); |
---|
945 | err = -EINVAL; |
---|
946 | goto _return_dev_set_drvdata; |
---|
947 | } |
---|
948 | |
---|
949 | for (i = 0; i < ARRAY_SIZE(mac_dev->port); i++) { |
---|
950 | #ifdef __rtems__ |
---|
951 | struct fman_ivars *ivars; |
---|
952 | device_t child; |
---|
953 | |
---|
954 | ivars = &mac_dev->ivars[i]; |
---|
955 | #endif /* __rtems__ */ |
---|
956 | /* Find the port node */ |
---|
957 | #ifndef __rtems__ |
---|
958 | dev_node = of_parse_phandle(mac_node, "fsl,fman-ports", i); |
---|
959 | #else /* __rtems__ */ |
---|
960 | dev_node = of_parse_phandle(&ivars->dn, mac_node, |
---|
961 | "fsl,fman-ports", i); |
---|
962 | #endif /* __rtems__ */ |
---|
963 | if (!dev_node) { |
---|
964 | dev_err(dev, "of_parse_phandle(%s, fsl,fman-ports) failed\n", |
---|
965 | mac_node->full_name); |
---|
966 | err = -EINVAL; |
---|
967 | goto _return_of_node_put; |
---|
968 | } |
---|
969 | |
---|
970 | #ifndef __rtems__ |
---|
971 | of_dev = of_find_device_by_node(dev_node); |
---|
972 | if (!of_dev) { |
---|
973 | dev_err(dev, "of_find_device_by_node(%s) failed\n", |
---|
974 | dev_node->full_name); |
---|
975 | err = -EINVAL; |
---|
976 | goto _return_of_node_put; |
---|
977 | } |
---|
978 | |
---|
979 | mac_dev->port[i] = fman_port_bind(&of_dev->dev); |
---|
980 | if (!mac_dev->port[i]) { |
---|
981 | dev_err(dev, "dev_get_drvdata(%s) failed\n", |
---|
982 | dev_node->full_name); |
---|
983 | err = -EINVAL; |
---|
984 | goto _return_of_node_put; |
---|
985 | } |
---|
986 | of_node_put(dev_node); |
---|
987 | #else /* __rtems__ */ |
---|
988 | ivars->of_dev.dev.of_node = dev_node; |
---|
989 | ivars->of_dev.dev.base = _of_dev->dev.base; |
---|
990 | ivars->fman = fman; |
---|
991 | |
---|
992 | child = device_add_child(_dev, "fman_port", -1); |
---|
993 | if (child == NULL) { |
---|
994 | kfree(ivars); |
---|
995 | goto _return_of_node_put; |
---|
996 | } |
---|
997 | |
---|
998 | device_set_ivars(child, ivars); |
---|
999 | |
---|
1000 | err = device_probe_and_attach(child); |
---|
1001 | if (err != 0) { |
---|
1002 | kfree(ivars); |
---|
1003 | goto _return_of_node_put; |
---|
1004 | } |
---|
1005 | |
---|
1006 | mac_dev->port[i] = dev_get_drvdata(&ivars->of_dev.dev); |
---|
1007 | #endif /* __rtems__ */ |
---|
1008 | } |
---|
1009 | |
---|
1010 | /* Get the PHY connection type */ |
---|
1011 | phy_if = of_get_phy_mode(mac_node); |
---|
1012 | if (phy_if < 0) { |
---|
1013 | dev_warn(dev, |
---|
1014 | "of_get_phy_mode() for %s failed. Defaulting to SGMII\n", |
---|
1015 | mac_node->full_name); |
---|
1016 | phy_if = PHY_INTERFACE_MODE_SGMII; |
---|
1017 | } |
---|
1018 | priv->phy_if = phy_if; |
---|
1019 | |
---|
1020 | priv->speed = phy2speed[priv->phy_if]; |
---|
1021 | priv->max_speed = priv->speed; |
---|
1022 | mac_dev->if_support = DTSEC_SUPPORTED; |
---|
1023 | /* We don't support half-duplex in SGMII mode */ |
---|
1024 | if (priv->phy_if == PHY_INTERFACE_MODE_SGMII) |
---|
1025 | mac_dev->if_support &= ~(SUPPORTED_10baseT_Half | |
---|
1026 | SUPPORTED_100baseT_Half); |
---|
1027 | |
---|
1028 | /* Gigabit support (no half-duplex) */ |
---|
1029 | if (priv->max_speed == 1000) |
---|
1030 | mac_dev->if_support |= SUPPORTED_1000baseT_Full; |
---|
1031 | |
---|
1032 | /* The 10G interface only supports one mode */ |
---|
1033 | if (priv->phy_if == PHY_INTERFACE_MODE_XGMII) |
---|
1034 | mac_dev->if_support = SUPPORTED_10000baseT_Full; |
---|
1035 | |
---|
1036 | /* Get the rest of the PHY information */ |
---|
1037 | #ifndef __rtems__ |
---|
1038 | priv->phy_node = of_parse_phandle(mac_node, "phy-handle", 0); |
---|
1039 | if (!priv->phy_node && of_phy_is_fixed_link(mac_node)) { |
---|
1040 | struct phy_device *phy; |
---|
1041 | |
---|
1042 | err = of_phy_register_fixed_link(mac_node); |
---|
1043 | if (err) |
---|
1044 | goto _return_dev_set_drvdata; |
---|
1045 | |
---|
1046 | priv->fixed_link = kzalloc(sizeof(*priv->fixed_link), |
---|
1047 | GFP_KERNEL); |
---|
1048 | if (!priv->fixed_link) { |
---|
1049 | err = -ENOMEM; |
---|
1050 | goto _return_dev_set_drvdata; |
---|
1051 | } |
---|
1052 | |
---|
1053 | priv->phy_node = of_node_get(mac_node); |
---|
1054 | phy = of_phy_find_device(priv->phy_node); |
---|
1055 | if (!phy) { |
---|
1056 | err = -EINVAL; |
---|
1057 | goto _return_dev_set_drvdata; |
---|
1058 | } |
---|
1059 | |
---|
1060 | priv->fixed_link->link = phy->link; |
---|
1061 | priv->fixed_link->speed = phy->speed; |
---|
1062 | priv->fixed_link->duplex = phy->duplex; |
---|
1063 | priv->fixed_link->pause = phy->pause; |
---|
1064 | priv->fixed_link->asym_pause = phy->asym_pause; |
---|
1065 | |
---|
1066 | put_device(&phy->mdio.dev); |
---|
1067 | } |
---|
1068 | #else /* __rtems__ */ |
---|
1069 | priv->phy_node = of_parse_phandle(&priv->phy_node_storage, mac_node, |
---|
1070 | "phy-handle", 0); |
---|
1071 | mac_dev->phy_dev = of_phy_find_device(priv->phy_node); |
---|
1072 | #endif /* __rtems__ */ |
---|
1073 | |
---|
1074 | err = mac_dev->init(mac_dev); |
---|
1075 | if (err < 0) { |
---|
1076 | dev_err(dev, "mac_dev->init() = %d\n", err); |
---|
1077 | of_node_put(priv->phy_node); |
---|
1078 | goto _return_dev_set_drvdata; |
---|
1079 | } |
---|
1080 | |
---|
1081 | /* pause frame autonegotiation enabled */ |
---|
1082 | mac_dev->autoneg_pause = true; |
---|
1083 | |
---|
1084 | /* By intializing the values to false, force FMD to enable PAUSE frames |
---|
1085 | * on RX and TX |
---|
1086 | */ |
---|
1087 | mac_dev->rx_pause_req = true; |
---|
1088 | mac_dev->tx_pause_req = true; |
---|
1089 | mac_dev->rx_pause_active = false; |
---|
1090 | mac_dev->tx_pause_active = false; |
---|
1091 | err = fman_set_mac_active_pause(mac_dev, true, true); |
---|
1092 | if (err < 0) |
---|
1093 | dev_err(dev, "fman_set_mac_active_pause() = %d\n", err); |
---|
1094 | |
---|
1095 | dev_info(dev, "FMan MAC address: %02hx:%02hx:%02hx:%02hx:%02hx:%02hx\n", |
---|
1096 | mac_dev->addr[0], mac_dev->addr[1], mac_dev->addr[2], |
---|
1097 | mac_dev->addr[3], mac_dev->addr[4], mac_dev->addr[5]); |
---|
1098 | |
---|
1099 | priv->eth_dev = dpaa_eth_add_device(fman_id, mac_dev, mac_node); |
---|
1100 | if (IS_ERR(priv->eth_dev)) { |
---|
1101 | dev_err(dev, "failed to add Ethernet platform device for MAC %d\n", |
---|
1102 | priv->cell_index); |
---|
1103 | priv->eth_dev = NULL; |
---|
1104 | } |
---|
1105 | |
---|
1106 | goto _return; |
---|
1107 | |
---|
1108 | _return_of_node_put: |
---|
1109 | #ifndef __rtems__ |
---|
1110 | of_node_put(dev_node); |
---|
1111 | #endif /* __rtems__ */ |
---|
1112 | _return_dev_set_drvdata: |
---|
1113 | kfree(priv->fixed_link); |
---|
1114 | dev_set_drvdata(dev, NULL); |
---|
1115 | _return: |
---|
1116 | return err; |
---|
1117 | } |
---|
1118 | |
---|
1119 | #ifndef __rtems__ |
---|
1120 | static struct platform_driver mac_driver = { |
---|
1121 | .driver = { |
---|
1122 | .name = KBUILD_MODNAME, |
---|
1123 | .of_match_table = mac_match, |
---|
1124 | }, |
---|
1125 | .probe = mac_probe, |
---|
1126 | }; |
---|
1127 | |
---|
1128 | builtin_platform_driver(mac_driver); |
---|
1129 | #else /* __rtems__ */ |
---|
1130 | #include <sys/cdefs.h> |
---|
1131 | #include <sys/param.h> |
---|
1132 | #include <sys/systm.h> |
---|
1133 | #include <sys/bus.h> |
---|
1134 | #include <sys/kernel.h> |
---|
1135 | |
---|
1136 | #include <rtems/bsd/local/miibus_if.h> |
---|
1137 | |
---|
1138 | static int |
---|
1139 | fman_mac_dev_probe(device_t dev) |
---|
1140 | { |
---|
1141 | struct fman_ivars *ivars = device_get_ivars(dev); |
---|
1142 | int err; |
---|
1143 | |
---|
1144 | err = mac_probe(dev, &ivars->of_dev, ivars->fman); |
---|
1145 | if (err == 0) { |
---|
1146 | device_set_desc(dev, "FMan MAC"); |
---|
1147 | return (BUS_PROBE_SPECIFIC); |
---|
1148 | } else { |
---|
1149 | return (ENXIO); |
---|
1150 | } |
---|
1151 | } |
---|
1152 | |
---|
1153 | static device_method_t fman_mac_methods[] = { |
---|
1154 | /* Device interface */ |
---|
1155 | DEVMETHOD(device_probe, fman_mac_dev_probe), |
---|
1156 | DEVMETHOD(device_attach, fman_mac_dev_attach), |
---|
1157 | DEVMETHOD(device_detach, fman_mac_dev_detach), |
---|
1158 | DEVMETHOD(device_suspend, bus_generic_suspend), |
---|
1159 | DEVMETHOD(device_resume, bus_generic_resume), |
---|
1160 | DEVMETHOD(device_shutdown, bus_generic_shutdown), |
---|
1161 | |
---|
1162 | /* MII Interface */ |
---|
1163 | DEVMETHOD(miibus_readreg, fman_mac_miibus_read_reg), |
---|
1164 | DEVMETHOD(miibus_writereg, fman_mac_miibus_write_reg), |
---|
1165 | DEVMETHOD(miibus_statchg, fman_mac_miibus_statchg), |
---|
1166 | |
---|
1167 | DEVMETHOD_END |
---|
1168 | }; |
---|
1169 | |
---|
1170 | driver_t fman_mac_driver = { |
---|
1171 | .name = "fman_mac", |
---|
1172 | .methods = fman_mac_methods, |
---|
1173 | .size = sizeof(struct fman_mac_softc) |
---|
1174 | }; |
---|
1175 | |
---|
1176 | static devclass_t fman_mac_devclass; |
---|
1177 | |
---|
1178 | DRIVER_MODULE(fman_mac, fman, fman_mac_driver, fman_mac_devclass, 0, 0); |
---|
1179 | DRIVER_MODULE(miibus, fman_mac, miibus_driver, miibus_devclass, 0, 0); |
---|
1180 | |
---|
1181 | MODULE_DEPEND(fman_mac, ether, 1, 1, 1); |
---|
1182 | MODULE_DEPEND(fman_mac, miibus, 1, 1, 1); |
---|
1183 | #endif /* __rtems__ */ |
---|