]>
Commit | Line | Data |
---|---|---|
48257c4f PA |
1 | /* |
2 | * Combined Ethernet driver for Motorola MPC8xx and MPC82xx. | |
3 | * | |
9b8ee8e7 | 4 | * Copyright (c) 2003 Intracom S.A. |
48257c4f | 5 | * by Pantelis Antoniou <panto@intracom.gr> |
9b8ee8e7 VB |
6 | * |
7 | * 2005 (c) MontaVista Software, Inc. | |
48257c4f PA |
8 | * Vitaly Bordug <vbordug@ru.mvista.com> |
9 | * | |
10 | * Heavily based on original FEC driver by Dan Malek <dan@embeddededge.com> | |
11 | * and modifications by Joakim Tjernlund <joakim.tjernlund@lumentis.se> | |
12 | * | |
9b8ee8e7 VB |
13 | * This file is licensed under the terms of the GNU General Public License |
14 | * version 2. This program is licensed "as is" without any warranty of any | |
48257c4f PA |
15 | * kind, whether express or implied. |
16 | */ | |
17 | ||
48257c4f PA |
18 | #include <linux/module.h> |
19 | #include <linux/kernel.h> | |
20 | #include <linux/types.h> | |
48257c4f PA |
21 | #include <linux/string.h> |
22 | #include <linux/ptrace.h> | |
23 | #include <linux/errno.h> | |
24 | #include <linux/ioport.h> | |
25 | #include <linux/slab.h> | |
26 | #include <linux/interrupt.h> | |
48257c4f PA |
27 | #include <linux/init.h> |
28 | #include <linux/delay.h> | |
29 | #include <linux/netdevice.h> | |
30 | #include <linux/etherdevice.h> | |
31 | #include <linux/skbuff.h> | |
32 | #include <linux/spinlock.h> | |
33 | #include <linux/mii.h> | |
34 | #include <linux/ethtool.h> | |
35 | #include <linux/bitops.h> | |
36 | #include <linux/fs.h> | |
f7b99969 | 37 | #include <linux/platform_device.h> |
5b4b8454 | 38 | #include <linux/phy.h> |
aa73832c GL |
39 | #include <linux/of.h> |
40 | #include <linux/of_mdio.h> | |
b219108c | 41 | #include <linux/of_platform.h> |
8725f25a | 42 | #include <linux/of_gpio.h> |
48257c4f PA |
43 | |
44 | #include <linux/vmalloc.h> | |
48257c4f PA |
45 | #include <asm/pgtable.h> |
46 | #include <asm/irq.h> | |
47 | #include <asm/uaccess.h> | |
48 | ||
49 | #include "fs_enet.h" | |
50 | ||
51 | /*************************************************/ | |
52 | ||
48257c4f PA |
53 | MODULE_AUTHOR("Pantelis Antoniou <panto@intracom.gr>"); |
54 | MODULE_DESCRIPTION("Freescale Ethernet Driver"); | |
55 | MODULE_LICENSE("GPL"); | |
56 | MODULE_VERSION(DRV_MODULE_VERSION); | |
57 | ||
31a5bb04 | 58 | static int fs_enet_debug = -1; /* -1 == use FS_ENET_DEF_MSG_ENABLE as value */ |
8d3b33f6 | 59 | module_param(fs_enet_debug, int, 0); |
48257c4f PA |
60 | MODULE_PARM_DESC(fs_enet_debug, |
61 | "Freescale bitmapped debugging message enable value"); | |
62 | ||
9b8ee8e7 VB |
63 | #ifdef CONFIG_NET_POLL_CONTROLLER |
64 | static void fs_enet_netpoll(struct net_device *dev); | |
65 | #endif | |
48257c4f PA |
66 | |
67 | static void fs_set_multicast_list(struct net_device *dev) | |
68 | { | |
69 | struct fs_enet_private *fep = netdev_priv(dev); | |
70 | ||
71 | (*fep->ops->set_multicast_list)(dev); | |
72 | } | |
73 | ||
0d0d9c15 SW |
74 | static void skb_align(struct sk_buff *skb, int align) |
75 | { | |
76 | int off = ((unsigned long)skb->data) & (align - 1); | |
77 | ||
78 | if (off) | |
79 | skb_reserve(skb, align - off); | |
80 | } | |
81 | ||
48257c4f | 82 | /* NAPI receive function */ |
bea3348e | 83 | static int fs_enet_rx_napi(struct napi_struct *napi, int budget) |
48257c4f | 84 | { |
bea3348e | 85 | struct fs_enet_private *fep = container_of(napi, struct fs_enet_private, napi); |
f860f49e | 86 | struct net_device *dev = fep->ndev; |
48257c4f | 87 | const struct fs_platform_info *fpi = fep->fpi; |
31a5bb04 | 88 | cbd_t __iomem *bdp; |
48257c4f PA |
89 | struct sk_buff *skb, *skbn, *skbt; |
90 | int received = 0; | |
91 | u16 pkt_len, sc; | |
92 | int curidx; | |
48257c4f | 93 | |
48257c4f PA |
94 | /* |
95 | * First, grab all of the stats for the incoming packet. | |
96 | * These get messed up if we get called due to a busy condition. | |
97 | */ | |
98 | bdp = fep->cur_rx; | |
99 | ||
100 | /* clear RX status bits for napi*/ | |
101 | (*fep->ops->napi_clear_rx_event)(dev); | |
102 | ||
103 | while (((sc = CBDR_SC(bdp)) & BD_ENET_RX_EMPTY) == 0) { | |
48257c4f PA |
104 | curidx = bdp - fep->rx_bd_base; |
105 | ||
106 | /* | |
107 | * Since we have allocated space to hold a complete frame, | |
108 | * the last indicator should be set. | |
109 | */ | |
110 | if ((sc & BD_ENET_RX_LAST) == 0) | |
fcb6a1c8 | 111 | dev_warn(fep->dev, "rcv is not +last\n"); |
48257c4f PA |
112 | |
113 | /* | |
9b8ee8e7 | 114 | * Check for errors. |
48257c4f PA |
115 | */ |
116 | if (sc & (BD_ENET_RX_LG | BD_ENET_RX_SH | BD_ENET_RX_CL | | |
117 | BD_ENET_RX_NO | BD_ENET_RX_CR | BD_ENET_RX_OV)) { | |
118 | fep->stats.rx_errors++; | |
119 | /* Frame too long or too short. */ | |
120 | if (sc & (BD_ENET_RX_LG | BD_ENET_RX_SH)) | |
121 | fep->stats.rx_length_errors++; | |
122 | /* Frame alignment */ | |
123 | if (sc & (BD_ENET_RX_NO | BD_ENET_RX_CL)) | |
124 | fep->stats.rx_frame_errors++; | |
125 | /* CRC Error */ | |
126 | if (sc & BD_ENET_RX_CR) | |
127 | fep->stats.rx_crc_errors++; | |
128 | /* FIFO overrun */ | |
129 | if (sc & BD_ENET_RX_OV) | |
130 | fep->stats.rx_crc_errors++; | |
131 | ||
132 | skb = fep->rx_skbuff[curidx]; | |
133 | ||
34e30d61 | 134 | dma_unmap_single(fep->dev, CBDR_BUFADDR(bdp), |
48257c4f PA |
135 | L1_CACHE_ALIGN(PKT_MAXBUF_SIZE), |
136 | DMA_FROM_DEVICE); | |
137 | ||
138 | skbn = skb; | |
139 | ||
140 | } else { | |
48257c4f PA |
141 | skb = fep->rx_skbuff[curidx]; |
142 | ||
34e30d61 | 143 | dma_unmap_single(fep->dev, CBDR_BUFADDR(bdp), |
48257c4f PA |
144 | L1_CACHE_ALIGN(PKT_MAXBUF_SIZE), |
145 | DMA_FROM_DEVICE); | |
146 | ||
147 | /* | |
148 | * Process the incoming frame. | |
149 | */ | |
150 | fep->stats.rx_packets++; | |
151 | pkt_len = CBDR_DATLEN(bdp) - 4; /* remove CRC */ | |
152 | fep->stats.rx_bytes += pkt_len + 4; | |
153 | ||
154 | if (pkt_len <= fpi->rx_copybreak) { | |
155 | /* +2 to make IP header L1 cache aligned */ | |
156 | skbn = dev_alloc_skb(pkt_len + 2); | |
157 | if (skbn != NULL) { | |
158 | skb_reserve(skbn, 2); /* align IP header */ | |
d626f62b ACM |
159 | skb_copy_from_linear_data(skb, |
160 | skbn->data, pkt_len); | |
48257c4f PA |
161 | /* swap */ |
162 | skbt = skb; | |
163 | skb = skbn; | |
164 | skbn = skbt; | |
165 | } | |
0d0d9c15 | 166 | } else { |
48257c4f PA |
167 | skbn = dev_alloc_skb(ENET_RX_FRSIZE); |
168 | ||
0d0d9c15 SW |
169 | if (skbn) |
170 | skb_align(skbn, ENET_RX_ALIGN); | |
171 | } | |
172 | ||
48257c4f | 173 | if (skbn != NULL) { |
48257c4f PA |
174 | skb_put(skb, pkt_len); /* Make room */ |
175 | skb->protocol = eth_type_trans(skb, dev); | |
176 | received++; | |
177 | netif_receive_skb(skb); | |
178 | } else { | |
fcb6a1c8 AG |
179 | dev_warn(fep->dev, |
180 | "Memory squeeze, dropping packet.\n"); | |
48257c4f PA |
181 | fep->stats.rx_dropped++; |
182 | skbn = skb; | |
183 | } | |
184 | } | |
185 | ||
186 | fep->rx_skbuff[curidx] = skbn; | |
187 | CBDW_BUFADDR(bdp, dma_map_single(fep->dev, skbn->data, | |
188 | L1_CACHE_ALIGN(PKT_MAXBUF_SIZE), | |
189 | DMA_FROM_DEVICE)); | |
190 | CBDW_DATLEN(bdp, 0); | |
191 | CBDW_SC(bdp, (sc & ~BD_ENET_RX_STATS) | BD_ENET_RX_EMPTY); | |
192 | ||
193 | /* | |
9b8ee8e7 | 194 | * Update BD pointer to next entry. |
48257c4f PA |
195 | */ |
196 | if ((sc & BD_ENET_RX_WRAP) == 0) | |
197 | bdp++; | |
198 | else | |
199 | bdp = fep->rx_bd_base; | |
200 | ||
201 | (*fep->ops->rx_bd_done)(dev); | |
bea3348e SH |
202 | |
203 | if (received >= budget) | |
204 | break; | |
48257c4f PA |
205 | } |
206 | ||
207 | fep->cur_rx = bdp; | |
208 | ||
f860f49e | 209 | if (received < budget) { |
bea3348e | 210 | /* done */ |
288379f0 | 211 | napi_complete(napi); |
bea3348e SH |
212 | (*fep->ops->napi_enable_rx)(dev); |
213 | } | |
214 | return received; | |
48257c4f PA |
215 | } |
216 | ||
217 | /* non NAPI receive function */ | |
218 | static int fs_enet_rx_non_napi(struct net_device *dev) | |
219 | { | |
220 | struct fs_enet_private *fep = netdev_priv(dev); | |
221 | const struct fs_platform_info *fpi = fep->fpi; | |
31a5bb04 | 222 | cbd_t __iomem *bdp; |
48257c4f PA |
223 | struct sk_buff *skb, *skbn, *skbt; |
224 | int received = 0; | |
225 | u16 pkt_len, sc; | |
226 | int curidx; | |
227 | /* | |
228 | * First, grab all of the stats for the incoming packet. | |
229 | * These get messed up if we get called due to a busy condition. | |
230 | */ | |
231 | bdp = fep->cur_rx; | |
232 | ||
233 | while (((sc = CBDR_SC(bdp)) & BD_ENET_RX_EMPTY) == 0) { | |
234 | ||
235 | curidx = bdp - fep->rx_bd_base; | |
236 | ||
237 | /* | |
238 | * Since we have allocated space to hold a complete frame, | |
239 | * the last indicator should be set. | |
240 | */ | |
241 | if ((sc & BD_ENET_RX_LAST) == 0) | |
fcb6a1c8 | 242 | dev_warn(fep->dev, "rcv is not +last\n"); |
48257c4f PA |
243 | |
244 | /* | |
9b8ee8e7 | 245 | * Check for errors. |
48257c4f PA |
246 | */ |
247 | if (sc & (BD_ENET_RX_LG | BD_ENET_RX_SH | BD_ENET_RX_CL | | |
248 | BD_ENET_RX_NO | BD_ENET_RX_CR | BD_ENET_RX_OV)) { | |
249 | fep->stats.rx_errors++; | |
250 | /* Frame too long or too short. */ | |
251 | if (sc & (BD_ENET_RX_LG | BD_ENET_RX_SH)) | |
252 | fep->stats.rx_length_errors++; | |
253 | /* Frame alignment */ | |
254 | if (sc & (BD_ENET_RX_NO | BD_ENET_RX_CL)) | |
255 | fep->stats.rx_frame_errors++; | |
256 | /* CRC Error */ | |
257 | if (sc & BD_ENET_RX_CR) | |
258 | fep->stats.rx_crc_errors++; | |
259 | /* FIFO overrun */ | |
260 | if (sc & BD_ENET_RX_OV) | |
261 | fep->stats.rx_crc_errors++; | |
262 | ||
263 | skb = fep->rx_skbuff[curidx]; | |
264 | ||
34e30d61 | 265 | dma_unmap_single(fep->dev, CBDR_BUFADDR(bdp), |
48257c4f PA |
266 | L1_CACHE_ALIGN(PKT_MAXBUF_SIZE), |
267 | DMA_FROM_DEVICE); | |
268 | ||
269 | skbn = skb; | |
270 | ||
271 | } else { | |
272 | ||
273 | skb = fep->rx_skbuff[curidx]; | |
274 | ||
34e30d61 | 275 | dma_unmap_single(fep->dev, CBDR_BUFADDR(bdp), |
48257c4f PA |
276 | L1_CACHE_ALIGN(PKT_MAXBUF_SIZE), |
277 | DMA_FROM_DEVICE); | |
278 | ||
279 | /* | |
280 | * Process the incoming frame. | |
281 | */ | |
282 | fep->stats.rx_packets++; | |
283 | pkt_len = CBDR_DATLEN(bdp) - 4; /* remove CRC */ | |
284 | fep->stats.rx_bytes += pkt_len + 4; | |
285 | ||
286 | if (pkt_len <= fpi->rx_copybreak) { | |
287 | /* +2 to make IP header L1 cache aligned */ | |
288 | skbn = dev_alloc_skb(pkt_len + 2); | |
289 | if (skbn != NULL) { | |
290 | skb_reserve(skbn, 2); /* align IP header */ | |
d626f62b ACM |
291 | skb_copy_from_linear_data(skb, |
292 | skbn->data, pkt_len); | |
48257c4f PA |
293 | /* swap */ |
294 | skbt = skb; | |
295 | skb = skbn; | |
296 | skbn = skbt; | |
297 | } | |
0d0d9c15 | 298 | } else { |
48257c4f PA |
299 | skbn = dev_alloc_skb(ENET_RX_FRSIZE); |
300 | ||
0d0d9c15 SW |
301 | if (skbn) |
302 | skb_align(skbn, ENET_RX_ALIGN); | |
303 | } | |
304 | ||
48257c4f | 305 | if (skbn != NULL) { |
48257c4f PA |
306 | skb_put(skb, pkt_len); /* Make room */ |
307 | skb->protocol = eth_type_trans(skb, dev); | |
308 | received++; | |
309 | netif_rx(skb); | |
310 | } else { | |
fcb6a1c8 AG |
311 | dev_warn(fep->dev, |
312 | "Memory squeeze, dropping packet.\n"); | |
48257c4f PA |
313 | fep->stats.rx_dropped++; |
314 | skbn = skb; | |
315 | } | |
316 | } | |
317 | ||
318 | fep->rx_skbuff[curidx] = skbn; | |
319 | CBDW_BUFADDR(bdp, dma_map_single(fep->dev, skbn->data, | |
320 | L1_CACHE_ALIGN(PKT_MAXBUF_SIZE), | |
321 | DMA_FROM_DEVICE)); | |
322 | CBDW_DATLEN(bdp, 0); | |
323 | CBDW_SC(bdp, (sc & ~BD_ENET_RX_STATS) | BD_ENET_RX_EMPTY); | |
324 | ||
325 | /* | |
9b8ee8e7 | 326 | * Update BD pointer to next entry. |
48257c4f PA |
327 | */ |
328 | if ((sc & BD_ENET_RX_WRAP) == 0) | |
329 | bdp++; | |
330 | else | |
331 | bdp = fep->rx_bd_base; | |
332 | ||
333 | (*fep->ops->rx_bd_done)(dev); | |
334 | } | |
335 | ||
336 | fep->cur_rx = bdp; | |
337 | ||
338 | return 0; | |
339 | } | |
340 | ||
341 | static void fs_enet_tx(struct net_device *dev) | |
342 | { | |
343 | struct fs_enet_private *fep = netdev_priv(dev); | |
31a5bb04 | 344 | cbd_t __iomem *bdp; |
48257c4f PA |
345 | struct sk_buff *skb; |
346 | int dirtyidx, do_wake, do_restart; | |
347 | u16 sc; | |
348 | ||
aa90f503 | 349 | spin_lock(&fep->tx_lock); |
48257c4f PA |
350 | bdp = fep->dirty_tx; |
351 | ||
352 | do_wake = do_restart = 0; | |
353 | while (((sc = CBDR_SC(bdp)) & BD_ENET_TX_READY) == 0) { | |
48257c4f PA |
354 | dirtyidx = bdp - fep->tx_bd_base; |
355 | ||
356 | if (fep->tx_free == fep->tx_ring) | |
357 | break; | |
358 | ||
359 | skb = fep->tx_skbuff[dirtyidx]; | |
360 | ||
361 | /* | |
9b8ee8e7 | 362 | * Check for errors. |
48257c4f PA |
363 | */ |
364 | if (sc & (BD_ENET_TX_HB | BD_ENET_TX_LC | | |
365 | BD_ENET_TX_RL | BD_ENET_TX_UN | BD_ENET_TX_CSL)) { | |
366 | ||
367 | if (sc & BD_ENET_TX_HB) /* No heartbeat */ | |
368 | fep->stats.tx_heartbeat_errors++; | |
369 | if (sc & BD_ENET_TX_LC) /* Late collision */ | |
370 | fep->stats.tx_window_errors++; | |
371 | if (sc & BD_ENET_TX_RL) /* Retrans limit */ | |
372 | fep->stats.tx_aborted_errors++; | |
373 | if (sc & BD_ENET_TX_UN) /* Underrun */ | |
374 | fep->stats.tx_fifo_errors++; | |
375 | if (sc & BD_ENET_TX_CSL) /* Carrier lost */ | |
376 | fep->stats.tx_carrier_errors++; | |
377 | ||
378 | if (sc & (BD_ENET_TX_LC | BD_ENET_TX_RL | BD_ENET_TX_UN)) { | |
379 | fep->stats.tx_errors++; | |
380 | do_restart = 1; | |
381 | } | |
382 | } else | |
383 | fep->stats.tx_packets++; | |
384 | ||
fcb6a1c8 AG |
385 | if (sc & BD_ENET_TX_READY) { |
386 | dev_warn(fep->dev, | |
387 | "HEY! Enet xmit interrupt and TX_READY.\n"); | |
388 | } | |
48257c4f PA |
389 | |
390 | /* | |
391 | * Deferred means some collisions occurred during transmit, | |
392 | * but we eventually sent the packet OK. | |
393 | */ | |
394 | if (sc & BD_ENET_TX_DEF) | |
395 | fep->stats.collisions++; | |
396 | ||
397 | /* unmap */ | |
34e30d61 PA |
398 | dma_unmap_single(fep->dev, CBDR_BUFADDR(bdp), |
399 | skb->len, DMA_TO_DEVICE); | |
48257c4f PA |
400 | |
401 | /* | |
9b8ee8e7 | 402 | * Free the sk buffer associated with this last transmit. |
48257c4f PA |
403 | */ |
404 | dev_kfree_skb_irq(skb); | |
405 | fep->tx_skbuff[dirtyidx] = NULL; | |
406 | ||
407 | /* | |
9b8ee8e7 | 408 | * Update pointer to next buffer descriptor to be transmitted. |
48257c4f PA |
409 | */ |
410 | if ((sc & BD_ENET_TX_WRAP) == 0) | |
411 | bdp++; | |
412 | else | |
413 | bdp = fep->tx_bd_base; | |
414 | ||
415 | /* | |
416 | * Since we have freed up a buffer, the ring is no longer | |
417 | * full. | |
418 | */ | |
419 | if (!fep->tx_free++) | |
420 | do_wake = 1; | |
421 | } | |
422 | ||
423 | fep->dirty_tx = bdp; | |
424 | ||
425 | if (do_restart) | |
426 | (*fep->ops->tx_restart)(dev); | |
427 | ||
aa90f503 | 428 | spin_unlock(&fep->tx_lock); |
48257c4f PA |
429 | |
430 | if (do_wake) | |
431 | netif_wake_queue(dev); | |
432 | } | |
433 | ||
434 | /* | |
435 | * The interrupt handler. | |
436 | * This is called from the MPC core interrupt. | |
437 | */ | |
438 | static irqreturn_t | |
7d12e780 | 439 | fs_enet_interrupt(int irq, void *dev_id) |
48257c4f PA |
440 | { |
441 | struct net_device *dev = dev_id; | |
442 | struct fs_enet_private *fep; | |
443 | const struct fs_platform_info *fpi; | |
444 | u32 int_events; | |
445 | u32 int_clr_events; | |
446 | int nr, napi_ok; | |
447 | int handled; | |
448 | ||
449 | fep = netdev_priv(dev); | |
450 | fpi = fep->fpi; | |
451 | ||
452 | nr = 0; | |
453 | while ((int_events = (*fep->ops->get_int_events)(dev)) != 0) { | |
48257c4f PA |
454 | nr++; |
455 | ||
456 | int_clr_events = int_events; | |
457 | if (fpi->use_napi) | |
458 | int_clr_events &= ~fep->ev_napi_rx; | |
459 | ||
460 | (*fep->ops->clear_int_events)(dev, int_clr_events); | |
461 | ||
462 | if (int_events & fep->ev_err) | |
463 | (*fep->ops->ev_error)(dev, int_events); | |
464 | ||
465 | if (int_events & fep->ev_rx) { | |
466 | if (!fpi->use_napi) | |
467 | fs_enet_rx_non_napi(dev); | |
468 | else { | |
bea3348e | 469 | napi_ok = napi_schedule_prep(&fep->napi); |
48257c4f PA |
470 | |
471 | (*fep->ops->napi_disable_rx)(dev); | |
472 | (*fep->ops->clear_int_events)(dev, fep->ev_napi_rx); | |
473 | ||
474 | /* NOTE: it is possible for FCCs in NAPI mode */ | |
475 | /* to submit a spurious interrupt while in poll */ | |
476 | if (napi_ok) | |
288379f0 | 477 | __napi_schedule(&fep->napi); |
48257c4f PA |
478 | } |
479 | } | |
480 | ||
481 | if (int_events & fep->ev_tx) | |
482 | fs_enet_tx(dev); | |
483 | } | |
484 | ||
485 | handled = nr > 0; | |
486 | return IRQ_RETVAL(handled); | |
487 | } | |
488 | ||
489 | void fs_init_bds(struct net_device *dev) | |
490 | { | |
491 | struct fs_enet_private *fep = netdev_priv(dev); | |
31a5bb04 | 492 | cbd_t __iomem *bdp; |
48257c4f PA |
493 | struct sk_buff *skb; |
494 | int i; | |
495 | ||
496 | fs_cleanup_bds(dev); | |
497 | ||
498 | fep->dirty_tx = fep->cur_tx = fep->tx_bd_base; | |
499 | fep->tx_free = fep->tx_ring; | |
500 | fep->cur_rx = fep->rx_bd_base; | |
501 | ||
502 | /* | |
9b8ee8e7 | 503 | * Initialize the receive buffer descriptors. |
48257c4f PA |
504 | */ |
505 | for (i = 0, bdp = fep->rx_bd_base; i < fep->rx_ring; i++, bdp++) { | |
506 | skb = dev_alloc_skb(ENET_RX_FRSIZE); | |
507 | if (skb == NULL) { | |
fcb6a1c8 AG |
508 | dev_warn(fep->dev, |
509 | "Memory squeeze, unable to allocate skb\n"); | |
48257c4f PA |
510 | break; |
511 | } | |
0d0d9c15 | 512 | skb_align(skb, ENET_RX_ALIGN); |
48257c4f | 513 | fep->rx_skbuff[i] = skb; |
48257c4f PA |
514 | CBDW_BUFADDR(bdp, |
515 | dma_map_single(fep->dev, skb->data, | |
516 | L1_CACHE_ALIGN(PKT_MAXBUF_SIZE), | |
517 | DMA_FROM_DEVICE)); | |
518 | CBDW_DATLEN(bdp, 0); /* zero */ | |
519 | CBDW_SC(bdp, BD_ENET_RX_EMPTY | | |
520 | ((i < fep->rx_ring - 1) ? 0 : BD_SC_WRAP)); | |
521 | } | |
522 | /* | |
9b8ee8e7 | 523 | * if we failed, fillup remainder |
48257c4f PA |
524 | */ |
525 | for (; i < fep->rx_ring; i++, bdp++) { | |
526 | fep->rx_skbuff[i] = NULL; | |
527 | CBDW_SC(bdp, (i < fep->rx_ring - 1) ? 0 : BD_SC_WRAP); | |
528 | } | |
529 | ||
530 | /* | |
9b8ee8e7 | 531 | * ...and the same for transmit. |
48257c4f PA |
532 | */ |
533 | for (i = 0, bdp = fep->tx_bd_base; i < fep->tx_ring; i++, bdp++) { | |
534 | fep->tx_skbuff[i] = NULL; | |
535 | CBDW_BUFADDR(bdp, 0); | |
536 | CBDW_DATLEN(bdp, 0); | |
537 | CBDW_SC(bdp, (i < fep->tx_ring - 1) ? 0 : BD_SC_WRAP); | |
538 | } | |
539 | } | |
540 | ||
541 | void fs_cleanup_bds(struct net_device *dev) | |
542 | { | |
543 | struct fs_enet_private *fep = netdev_priv(dev); | |
544 | struct sk_buff *skb; | |
31a5bb04 | 545 | cbd_t __iomem *bdp; |
48257c4f PA |
546 | int i; |
547 | ||
548 | /* | |
9b8ee8e7 | 549 | * Reset SKB transmit buffers. |
48257c4f | 550 | */ |
34e30d61 | 551 | for (i = 0, bdp = fep->tx_bd_base; i < fep->tx_ring; i++, bdp++) { |
48257c4f PA |
552 | if ((skb = fep->tx_skbuff[i]) == NULL) |
553 | continue; | |
554 | ||
555 | /* unmap */ | |
34e30d61 PA |
556 | dma_unmap_single(fep->dev, CBDR_BUFADDR(bdp), |
557 | skb->len, DMA_TO_DEVICE); | |
48257c4f PA |
558 | |
559 | fep->tx_skbuff[i] = NULL; | |
560 | dev_kfree_skb(skb); | |
561 | } | |
562 | ||
563 | /* | |
9b8ee8e7 | 564 | * Reset SKB receive buffers |
48257c4f | 565 | */ |
34e30d61 | 566 | for (i = 0, bdp = fep->rx_bd_base; i < fep->rx_ring; i++, bdp++) { |
48257c4f PA |
567 | if ((skb = fep->rx_skbuff[i]) == NULL) |
568 | continue; | |
569 | ||
570 | /* unmap */ | |
34e30d61 | 571 | dma_unmap_single(fep->dev, CBDR_BUFADDR(bdp), |
48257c4f PA |
572 | L1_CACHE_ALIGN(PKT_MAXBUF_SIZE), |
573 | DMA_FROM_DEVICE); | |
574 | ||
575 | fep->rx_skbuff[i] = NULL; | |
576 | ||
577 | dev_kfree_skb(skb); | |
578 | } | |
579 | } | |
580 | ||
581 | /**********************************************************************************/ | |
582 | ||
cb395eaf AG |
583 | #ifdef CONFIG_FS_ENET_MPC5121_FEC |
584 | /* | |
585 | * MPC5121 FEC requeries 4-byte alignment for TX data buffer! | |
586 | */ | |
587 | static struct sk_buff *tx_skb_align_workaround(struct net_device *dev, | |
588 | struct sk_buff *skb) | |
589 | { | |
590 | struct sk_buff *new_skb; | |
591 | struct fs_enet_private *fep = netdev_priv(dev); | |
592 | ||
593 | /* Alloc new skb */ | |
594 | new_skb = dev_alloc_skb(skb->len + 4); | |
595 | if (!new_skb) { | |
596 | if (net_ratelimit()) { | |
597 | dev_warn(fep->dev, | |
598 | "Memory squeeze, dropping tx packet.\n"); | |
599 | } | |
600 | return NULL; | |
601 | } | |
602 | ||
603 | /* Make sure new skb is properly aligned */ | |
604 | skb_align(new_skb, 4); | |
605 | ||
606 | /* Copy data to new skb ... */ | |
607 | skb_copy_from_linear_data(skb, new_skb->data, skb->len); | |
608 | skb_put(new_skb, skb->len); | |
609 | ||
610 | /* ... and free an old one */ | |
611 | dev_kfree_skb_any(skb); | |
612 | ||
613 | return new_skb; | |
614 | } | |
615 | #endif | |
616 | ||
48257c4f PA |
617 | static int fs_enet_start_xmit(struct sk_buff *skb, struct net_device *dev) |
618 | { | |
619 | struct fs_enet_private *fep = netdev_priv(dev); | |
31a5bb04 | 620 | cbd_t __iomem *bdp; |
48257c4f PA |
621 | int curidx; |
622 | u16 sc; | |
623 | unsigned long flags; | |
624 | ||
cb395eaf AG |
625 | #ifdef CONFIG_FS_ENET_MPC5121_FEC |
626 | if (((unsigned long)skb->data) & 0x3) { | |
627 | skb = tx_skb_align_workaround(dev, skb); | |
628 | if (!skb) { | |
629 | /* | |
630 | * We have lost packet due to memory allocation error | |
631 | * in tx_skb_align_workaround(). Hopefully original | |
632 | * skb is still valid, so try transmit it later. | |
633 | */ | |
634 | return NETDEV_TX_BUSY; | |
635 | } | |
636 | } | |
637 | #endif | |
48257c4f PA |
638 | spin_lock_irqsave(&fep->tx_lock, flags); |
639 | ||
640 | /* | |
9b8ee8e7 | 641 | * Fill in a Tx ring entry |
48257c4f PA |
642 | */ |
643 | bdp = fep->cur_tx; | |
644 | ||
645 | if (!fep->tx_free || (CBDR_SC(bdp) & BD_ENET_TX_READY)) { | |
646 | netif_stop_queue(dev); | |
647 | spin_unlock_irqrestore(&fep->tx_lock, flags); | |
648 | ||
649 | /* | |
650 | * Ooops. All transmit buffers are full. Bail out. | |
651 | * This should not happen, since the tx queue should be stopped. | |
652 | */ | |
fcb6a1c8 | 653 | dev_warn(fep->dev, "tx queue full!.\n"); |
48257c4f PA |
654 | return NETDEV_TX_BUSY; |
655 | } | |
656 | ||
657 | curidx = bdp - fep->tx_bd_base; | |
658 | /* | |
9b8ee8e7 | 659 | * Clear all of the status flags. |
48257c4f PA |
660 | */ |
661 | CBDC_SC(bdp, BD_ENET_TX_STATS); | |
662 | ||
663 | /* | |
9b8ee8e7 | 664 | * Save skb pointer. |
48257c4f PA |
665 | */ |
666 | fep->tx_skbuff[curidx] = skb; | |
667 | ||
668 | fep->stats.tx_bytes += skb->len; | |
669 | ||
670 | /* | |
9b8ee8e7 | 671 | * Push the data cache so the CPM does not get stale memory data. |
48257c4f PA |
672 | */ |
673 | CBDW_BUFADDR(bdp, dma_map_single(fep->dev, | |
674 | skb->data, skb->len, DMA_TO_DEVICE)); | |
675 | CBDW_DATLEN(bdp, skb->len); | |
676 | ||
48257c4f | 677 | /* |
9b8ee8e7 | 678 | * If this was the last BD in the ring, start at the beginning again. |
48257c4f PA |
679 | */ |
680 | if ((CBDR_SC(bdp) & BD_ENET_TX_WRAP) == 0) | |
681 | fep->cur_tx++; | |
682 | else | |
683 | fep->cur_tx = fep->tx_bd_base; | |
684 | ||
685 | if (!--fep->tx_free) | |
686 | netif_stop_queue(dev); | |
687 | ||
688 | /* Trigger transmission start */ | |
689 | sc = BD_ENET_TX_READY | BD_ENET_TX_INTR | | |
690 | BD_ENET_TX_LAST | BD_ENET_TX_TC; | |
691 | ||
692 | /* note that while FEC does not have this bit | |
693 | * it marks it as available for software use | |
694 | * yay for hw reuse :) */ | |
695 | if (skb->len <= 60) | |
696 | sc |= BD_ENET_TX_PAD; | |
697 | CBDS_SC(bdp, sc); | |
698 | ||
699 | (*fep->ops->tx_kickstart)(dev); | |
700 | ||
701 | spin_unlock_irqrestore(&fep->tx_lock, flags); | |
702 | ||
703 | return NETDEV_TX_OK; | |
704 | } | |
705 | ||
48257c4f PA |
706 | static void fs_timeout(struct net_device *dev) |
707 | { | |
708 | struct fs_enet_private *fep = netdev_priv(dev); | |
709 | unsigned long flags; | |
710 | int wake = 0; | |
711 | ||
712 | fep->stats.tx_errors++; | |
713 | ||
714 | spin_lock_irqsave(&fep->lock, flags); | |
715 | ||
716 | if (dev->flags & IFF_UP) { | |
5b4b8454 | 717 | phy_stop(fep->phydev); |
48257c4f PA |
718 | (*fep->ops->stop)(dev); |
719 | (*fep->ops->restart)(dev); | |
5b4b8454 | 720 | phy_start(fep->phydev); |
48257c4f PA |
721 | } |
722 | ||
5b4b8454 | 723 | phy_start(fep->phydev); |
48257c4f PA |
724 | wake = fep->tx_free && !(CBDR_SC(fep->cur_tx) & BD_ENET_TX_READY); |
725 | spin_unlock_irqrestore(&fep->lock, flags); | |
726 | ||
727 | if (wake) | |
728 | netif_wake_queue(dev); | |
729 | } | |
730 | ||
5b4b8454 VB |
731 | /*----------------------------------------------------------------------------- |
732 | * generic link-change handler - should be sufficient for most cases | |
733 | *-----------------------------------------------------------------------------*/ | |
734 | static void generic_adjust_link(struct net_device *dev) | |
735 | { | |
0fb300fa SW |
736 | struct fs_enet_private *fep = netdev_priv(dev); |
737 | struct phy_device *phydev = fep->phydev; | |
738 | int new_state = 0; | |
739 | ||
740 | if (phydev->link) { | |
741 | /* adjust to duplex mode */ | |
742 | if (phydev->duplex != fep->oldduplex) { | |
743 | new_state = 1; | |
744 | fep->oldduplex = phydev->duplex; | |
745 | } | |
746 | ||
747 | if (phydev->speed != fep->oldspeed) { | |
748 | new_state = 1; | |
749 | fep->oldspeed = phydev->speed; | |
750 | } | |
751 | ||
752 | if (!fep->oldlink) { | |
753 | new_state = 1; | |
754 | fep->oldlink = 1; | |
0fb300fa SW |
755 | } |
756 | ||
757 | if (new_state) | |
758 | fep->ops->restart(dev); | |
759 | } else if (fep->oldlink) { | |
760 | new_state = 1; | |
761 | fep->oldlink = 0; | |
762 | fep->oldspeed = 0; | |
763 | fep->oldduplex = -1; | |
0fb300fa SW |
764 | } |
765 | ||
766 | if (new_state && netif_msg_link(fep)) | |
767 | phy_print_status(phydev); | |
5b4b8454 VB |
768 | } |
769 | ||
770 | ||
771 | static void fs_adjust_link(struct net_device *dev) | |
772 | { | |
773 | struct fs_enet_private *fep = netdev_priv(dev); | |
774 | unsigned long flags; | |
775 | ||
776 | spin_lock_irqsave(&fep->lock, flags); | |
777 | ||
778 | if(fep->ops->adjust_link) | |
779 | fep->ops->adjust_link(dev); | |
780 | else | |
781 | generic_adjust_link(dev); | |
782 | ||
783 | spin_unlock_irqrestore(&fep->lock, flags); | |
784 | } | |
785 | ||
786 | static int fs_init_phy(struct net_device *dev) | |
787 | { | |
788 | struct fs_enet_private *fep = netdev_priv(dev); | |
789 | struct phy_device *phydev; | |
790 | ||
791 | fep->oldlink = 0; | |
792 | fep->oldspeed = 0; | |
793 | fep->oldduplex = -1; | |
eedbc705 AV |
794 | |
795 | phydev = of_phy_connect(dev, fep->fpi->phy_node, &fs_adjust_link, 0, | |
796 | PHY_INTERFACE_MODE_MII); | |
797 | if (!phydev) { | |
798 | phydev = of_phy_connect_fixed_link(dev, &fs_adjust_link, | |
799 | PHY_INTERFACE_MODE_MII); | |
5b4b8454 | 800 | } |
eedbc705 AV |
801 | if (!phydev) { |
802 | dev_err(&dev->dev, "Could not attach to PHY\n"); | |
803 | return -ENODEV; | |
5b4b8454 VB |
804 | } |
805 | ||
806 | fep->phydev = phydev; | |
807 | ||
808 | return 0; | |
809 | } | |
810 | ||
48257c4f PA |
811 | static int fs_enet_open(struct net_device *dev) |
812 | { | |
813 | struct fs_enet_private *fep = netdev_priv(dev); | |
48257c4f | 814 | int r; |
5b4b8454 | 815 | int err; |
48257c4f | 816 | |
f4f62301 HS |
817 | /* to initialize the fep->cur_rx,... */ |
818 | /* not doing this, will cause a crash in fs_enet_rx_napi */ | |
819 | fs_init_bds(fep->ndev); | |
820 | ||
f860f49e SW |
821 | if (fep->fpi->use_napi) |
822 | napi_enable(&fep->napi); | |
bea3348e | 823 | |
48257c4f | 824 | /* Install our interrupt handler. */ |
31578140 KG |
825 | r = request_irq(fep->interrupt, fs_enet_interrupt, IRQF_SHARED, |
826 | "fs_enet-mac", dev); | |
48257c4f | 827 | if (r != 0) { |
fcb6a1c8 | 828 | dev_err(fep->dev, "Could not allocate FS_ENET IRQ!"); |
f860f49e SW |
829 | if (fep->fpi->use_napi) |
830 | napi_disable(&fep->napi); | |
48257c4f PA |
831 | return -EINVAL; |
832 | } | |
833 | ||
5b4b8454 | 834 | err = fs_init_phy(dev); |
f860f49e | 835 | if (err) { |
d7e094d4 | 836 | free_irq(fep->interrupt, dev); |
f860f49e SW |
837 | if (fep->fpi->use_napi) |
838 | napi_disable(&fep->napi); | |
5b4b8454 | 839 | return err; |
bea3348e | 840 | } |
5b4b8454 | 841 | phy_start(fep->phydev); |
48257c4f | 842 | |
c8f15686 AV |
843 | netif_start_queue(dev); |
844 | ||
48257c4f PA |
845 | return 0; |
846 | } | |
847 | ||
848 | static int fs_enet_close(struct net_device *dev) | |
849 | { | |
850 | struct fs_enet_private *fep = netdev_priv(dev); | |
48257c4f PA |
851 | unsigned long flags; |
852 | ||
853 | netif_stop_queue(dev); | |
854 | netif_carrier_off(dev); | |
9a3c243d LP |
855 | if (fep->fpi->use_napi) |
856 | napi_disable(&fep->napi); | |
5b4b8454 | 857 | phy_stop(fep->phydev); |
48257c4f PA |
858 | |
859 | spin_lock_irqsave(&fep->lock, flags); | |
aa90f503 | 860 | spin_lock(&fep->tx_lock); |
48257c4f | 861 | (*fep->ops->stop)(dev); |
aa90f503 | 862 | spin_unlock(&fep->tx_lock); |
48257c4f PA |
863 | spin_unlock_irqrestore(&fep->lock, flags); |
864 | ||
865 | /* release any irqs */ | |
5b4b8454 VB |
866 | phy_disconnect(fep->phydev); |
867 | fep->phydev = NULL; | |
31578140 | 868 | free_irq(fep->interrupt, dev); |
48257c4f PA |
869 | |
870 | return 0; | |
871 | } | |
872 | ||
873 | static struct net_device_stats *fs_enet_get_stats(struct net_device *dev) | |
874 | { | |
875 | struct fs_enet_private *fep = netdev_priv(dev); | |
876 | return &fep->stats; | |
877 | } | |
878 | ||
879 | /*************************************************************************/ | |
880 | ||
881 | static void fs_get_drvinfo(struct net_device *dev, | |
882 | struct ethtool_drvinfo *info) | |
883 | { | |
884 | strcpy(info->driver, DRV_MODULE_NAME); | |
885 | strcpy(info->version, DRV_MODULE_VERSION); | |
886 | } | |
887 | ||
888 | static int fs_get_regs_len(struct net_device *dev) | |
889 | { | |
890 | struct fs_enet_private *fep = netdev_priv(dev); | |
891 | ||
892 | return (*fep->ops->get_regs_len)(dev); | |
893 | } | |
894 | ||
895 | static void fs_get_regs(struct net_device *dev, struct ethtool_regs *regs, | |
896 | void *p) | |
897 | { | |
898 | struct fs_enet_private *fep = netdev_priv(dev); | |
899 | unsigned long flags; | |
900 | int r, len; | |
901 | ||
902 | len = regs->len; | |
903 | ||
904 | spin_lock_irqsave(&fep->lock, flags); | |
905 | r = (*fep->ops->get_regs)(dev, p, &len); | |
906 | spin_unlock_irqrestore(&fep->lock, flags); | |
907 | ||
908 | if (r == 0) | |
909 | regs->version = 0; | |
910 | } | |
911 | ||
912 | static int fs_get_settings(struct net_device *dev, struct ethtool_cmd *cmd) | |
913 | { | |
914 | struct fs_enet_private *fep = netdev_priv(dev); | |
dfd9a421 AV |
915 | |
916 | if (!fep->phydev) | |
917 | return -ENODEV; | |
918 | ||
5b4b8454 | 919 | return phy_ethtool_gset(fep->phydev, cmd); |
48257c4f PA |
920 | } |
921 | ||
922 | static int fs_set_settings(struct net_device *dev, struct ethtool_cmd *cmd) | |
923 | { | |
924 | struct fs_enet_private *fep = netdev_priv(dev); | |
dfd9a421 AV |
925 | |
926 | if (!fep->phydev) | |
927 | return -ENODEV; | |
928 | ||
929 | return phy_ethtool_sset(fep->phydev, cmd); | |
48257c4f PA |
930 | } |
931 | ||
932 | static int fs_nway_reset(struct net_device *dev) | |
933 | { | |
5b4b8454 | 934 | return 0; |
48257c4f PA |
935 | } |
936 | ||
937 | static u32 fs_get_msglevel(struct net_device *dev) | |
938 | { | |
939 | struct fs_enet_private *fep = netdev_priv(dev); | |
940 | return fep->msg_enable; | |
941 | } | |
942 | ||
943 | static void fs_set_msglevel(struct net_device *dev, u32 value) | |
944 | { | |
945 | struct fs_enet_private *fep = netdev_priv(dev); | |
946 | fep->msg_enable = value; | |
947 | } | |
948 | ||
7282d491 | 949 | static const struct ethtool_ops fs_ethtool_ops = { |
48257c4f PA |
950 | .get_drvinfo = fs_get_drvinfo, |
951 | .get_regs_len = fs_get_regs_len, | |
952 | .get_settings = fs_get_settings, | |
953 | .set_settings = fs_set_settings, | |
954 | .nway_reset = fs_nway_reset, | |
955 | .get_link = ethtool_op_get_link, | |
956 | .get_msglevel = fs_get_msglevel, | |
957 | .set_msglevel = fs_set_msglevel, | |
48257c4f | 958 | .set_tx_csum = ethtool_op_set_tx_csum, /* local! */ |
48257c4f PA |
959 | .set_sg = ethtool_op_set_sg, |
960 | .get_regs = fs_get_regs, | |
961 | }; | |
962 | ||
963 | static int fs_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) | |
964 | { | |
965 | struct fs_enet_private *fep = netdev_priv(dev); | |
48257c4f PA |
966 | |
967 | if (!netif_running(dev)) | |
968 | return -EINVAL; | |
969 | ||
28b04113 | 970 | return phy_mii_ioctl(fep->phydev, rq, cmd); |
48257c4f PA |
971 | } |
972 | ||
973 | extern int fs_mii_connect(struct net_device *dev); | |
974 | extern void fs_mii_disconnect(struct net_device *dev); | |
975 | ||
48257c4f PA |
976 | /**************************************************************************************/ |
977 | ||
976de6a8 SW |
978 | #ifdef CONFIG_FS_ENET_HAS_FEC |
979 | #define IS_FEC(match) ((match)->data == &fs_fec_ops) | |
980 | #else | |
981 | #define IS_FEC(match) 0 | |
982 | #endif | |
983 | ||
8c02acd7 AB |
984 | static const struct net_device_ops fs_enet_netdev_ops = { |
985 | .ndo_open = fs_enet_open, | |
986 | .ndo_stop = fs_enet_close, | |
987 | .ndo_get_stats = fs_enet_get_stats, | |
988 | .ndo_start_xmit = fs_enet_start_xmit, | |
989 | .ndo_tx_timeout = fs_timeout, | |
990 | .ndo_set_multicast_list = fs_set_multicast_list, | |
991 | .ndo_do_ioctl = fs_ioctl, | |
992 | .ndo_validate_addr = eth_validate_addr, | |
993 | .ndo_set_mac_address = eth_mac_addr, | |
994 | .ndo_change_mtu = eth_change_mtu, | |
995 | #ifdef CONFIG_NET_POLL_CONTROLLER | |
996 | .ndo_poll_controller = fs_enet_netpoll, | |
997 | #endif | |
998 | }; | |
999 | ||
2dc11581 | 1000 | static int __devinit fs_enet_probe(struct platform_device *ofdev, |
976de6a8 SW |
1001 | const struct of_device_id *match) |
1002 | { | |
1003 | struct net_device *ndev; | |
1004 | struct fs_enet_private *fep; | |
1005 | struct fs_platform_info *fpi; | |
1006 | const u32 *data; | |
1007 | const u8 *mac_addr; | |
1008 | int privsize, len, ret = -ENODEV; | |
1009 | ||
1010 | fpi = kzalloc(sizeof(*fpi), GFP_KERNEL); | |
1011 | if (!fpi) | |
1012 | return -ENOMEM; | |
1013 | ||
1014 | if (!IS_FEC(match)) { | |
61c7a080 | 1015 | data = of_get_property(ofdev->dev.of_node, "fsl,cpm-command", &len); |
976de6a8 SW |
1016 | if (!data || len != 4) |
1017 | goto out_free_fpi; | |
1018 | ||
1019 | fpi->cp_command = *data; | |
1020 | } | |
1021 | ||
1022 | fpi->rx_ring = 32; | |
1023 | fpi->tx_ring = 32; | |
1024 | fpi->rx_copybreak = 240; | |
f860f49e | 1025 | fpi->use_napi = 1; |
976de6a8 | 1026 | fpi->napi_weight = 17; |
61c7a080 GL |
1027 | fpi->phy_node = of_parse_phandle(ofdev->dev.of_node, "phy-handle", 0); |
1028 | if ((!fpi->phy_node) && (!of_get_property(ofdev->dev.of_node, "fixed-link", | |
aa73832c | 1029 | NULL))) |
976de6a8 SW |
1030 | goto out_free_fpi; |
1031 | ||
1032 | privsize = sizeof(*fep) + | |
1033 | sizeof(struct sk_buff **) * | |
1034 | (fpi->rx_ring + fpi->tx_ring); | |
1035 | ||
1036 | ndev = alloc_etherdev(privsize); | |
1037 | if (!ndev) { | |
1038 | ret = -ENOMEM; | |
e8f7f43a | 1039 | goto out_put; |
976de6a8 SW |
1040 | } |
1041 | ||
eedbc705 | 1042 | SET_NETDEV_DEV(ndev, &ofdev->dev); |
976de6a8 SW |
1043 | dev_set_drvdata(&ofdev->dev, ndev); |
1044 | ||
1045 | fep = netdev_priv(ndev); | |
1046 | fep->dev = &ofdev->dev; | |
f860f49e | 1047 | fep->ndev = ndev; |
976de6a8 SW |
1048 | fep->fpi = fpi; |
1049 | fep->ops = match->data; | |
1050 | ||
1051 | ret = fep->ops->setup_data(ndev); | |
1052 | if (ret) | |
1053 | goto out_free_dev; | |
1054 | ||
1055 | fep->rx_skbuff = (struct sk_buff **)&fep[1]; | |
1056 | fep->tx_skbuff = fep->rx_skbuff + fpi->rx_ring; | |
1057 | ||
1058 | spin_lock_init(&fep->lock); | |
1059 | spin_lock_init(&fep->tx_lock); | |
1060 | ||
61c7a080 | 1061 | mac_addr = of_get_mac_address(ofdev->dev.of_node); |
976de6a8 SW |
1062 | if (mac_addr) |
1063 | memcpy(ndev->dev_addr, mac_addr, 6); | |
1064 | ||
1065 | ret = fep->ops->allocate_bd(ndev); | |
1066 | if (ret) | |
1067 | goto out_cleanup_data; | |
1068 | ||
1069 | fep->rx_bd_base = fep->ring_base; | |
1070 | fep->tx_bd_base = fep->rx_bd_base + fpi->rx_ring; | |
1071 | ||
1072 | fep->tx_ring = fpi->tx_ring; | |
1073 | fep->rx_ring = fpi->rx_ring; | |
1074 | ||
8c02acd7 | 1075 | ndev->netdev_ops = &fs_enet_netdev_ops; |
976de6a8 | 1076 | ndev->watchdog_timeo = 2 * HZ; |
f860f49e SW |
1077 | if (fpi->use_napi) |
1078 | netif_napi_add(ndev, &fep->napi, fs_enet_rx_napi, | |
1079 | fpi->napi_weight); | |
1080 | ||
976de6a8 | 1081 | ndev->ethtool_ops = &fs_ethtool_ops; |
976de6a8 SW |
1082 | |
1083 | init_timer(&fep->phy_timer_list); | |
1084 | ||
1085 | netif_carrier_off(ndev); | |
1086 | ||
1087 | ret = register_netdev(ndev); | |
1088 | if (ret) | |
1089 | goto out_free_bd; | |
1090 | ||
fcb6a1c8 | 1091 | pr_info("%s: fs_enet: %pM\n", ndev->name, ndev->dev_addr); |
976de6a8 SW |
1092 | |
1093 | return 0; | |
1094 | ||
1095 | out_free_bd: | |
1096 | fep->ops->free_bd(ndev); | |
1097 | out_cleanup_data: | |
1098 | fep->ops->cleanup_data(ndev); | |
1099 | out_free_dev: | |
1100 | free_netdev(ndev); | |
1101 | dev_set_drvdata(&ofdev->dev, NULL); | |
e8f7f43a | 1102 | out_put: |
aa73832c | 1103 | of_node_put(fpi->phy_node); |
976de6a8 SW |
1104 | out_free_fpi: |
1105 | kfree(fpi); | |
1106 | return ret; | |
1107 | } | |
1108 | ||
2dc11581 | 1109 | static int fs_enet_remove(struct platform_device *ofdev) |
976de6a8 SW |
1110 | { |
1111 | struct net_device *ndev = dev_get_drvdata(&ofdev->dev); | |
1112 | struct fs_enet_private *fep = netdev_priv(ndev); | |
1113 | ||
1114 | unregister_netdev(ndev); | |
1115 | ||
1116 | fep->ops->free_bd(ndev); | |
1117 | fep->ops->cleanup_data(ndev); | |
1118 | dev_set_drvdata(fep->dev, NULL); | |
aa73832c | 1119 | of_node_put(fep->fpi->phy_node); |
976de6a8 SW |
1120 | free_netdev(ndev); |
1121 | return 0; | |
1122 | } | |
1123 | ||
1124 | static struct of_device_id fs_enet_match[] = { | |
1125 | #ifdef CONFIG_FS_ENET_HAS_SCC | |
1126 | { | |
1127 | .compatible = "fsl,cpm1-scc-enet", | |
1128 | .data = (void *)&fs_scc_ops, | |
1129 | }, | |
f4f62301 HS |
1130 | { |
1131 | .compatible = "fsl,cpm2-scc-enet", | |
1132 | .data = (void *)&fs_scc_ops, | |
1133 | }, | |
976de6a8 SW |
1134 | #endif |
1135 | #ifdef CONFIG_FS_ENET_HAS_FCC | |
1136 | { | |
1137 | .compatible = "fsl,cpm2-fcc-enet", | |
1138 | .data = (void *)&fs_fcc_ops, | |
1139 | }, | |
1140 | #endif | |
1141 | #ifdef CONFIG_FS_ENET_HAS_FEC | |
60ab4361 AG |
1142 | #ifdef CONFIG_FS_ENET_MPC5121_FEC |
1143 | { | |
1144 | .compatible = "fsl,mpc5121-fec", | |
1145 | .data = (void *)&fs_fec_ops, | |
1146 | }, | |
1147 | #else | |
976de6a8 SW |
1148 | { |
1149 | .compatible = "fsl,pq1-fec-enet", | |
1150 | .data = (void *)&fs_fec_ops, | |
1151 | }, | |
60ab4361 | 1152 | #endif |
976de6a8 SW |
1153 | #endif |
1154 | {} | |
1155 | }; | |
e72701ac | 1156 | MODULE_DEVICE_TABLE(of, fs_enet_match); |
976de6a8 SW |
1157 | |
1158 | static struct of_platform_driver fs_enet_driver = { | |
4018294b GL |
1159 | .driver = { |
1160 | .owner = THIS_MODULE, | |
1161 | .name = "fs_enet", | |
1162 | .of_match_table = fs_enet_match, | |
1163 | }, | |
976de6a8 SW |
1164 | .probe = fs_enet_probe, |
1165 | .remove = fs_enet_remove, | |
1166 | }; | |
1167 | ||
1168 | static int __init fs_init(void) | |
1169 | { | |
1d58ea30 | 1170 | return of_register_platform_driver(&fs_enet_driver); |
976de6a8 SW |
1171 | } |
1172 | ||
1173 | static void __exit fs_cleanup(void) | |
1174 | { | |
1175 | of_unregister_platform_driver(&fs_enet_driver); | |
976de6a8 | 1176 | } |
48257c4f | 1177 | |
9b8ee8e7 VB |
1178 | #ifdef CONFIG_NET_POLL_CONTROLLER |
1179 | static void fs_enet_netpoll(struct net_device *dev) | |
1180 | { | |
1181 | disable_irq(dev->irq); | |
7385d595 | 1182 | fs_enet_interrupt(dev->irq, dev); |
9b8ee8e7 VB |
1183 | enable_irq(dev->irq); |
1184 | } | |
1185 | #endif | |
1186 | ||
48257c4f PA |
1187 | /**************************************************************************************/ |
1188 | ||
1189 | module_init(fs_init); | |
1190 | module_exit(fs_cleanup); |