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> |
48257c4f PA |
39 | |
40 | #include <linux/vmalloc.h> | |
48257c4f PA |
41 | #include <asm/pgtable.h> |
42 | #include <asm/irq.h> | |
43 | #include <asm/uaccess.h> | |
44 | ||
976de6a8 SW |
45 | #ifdef CONFIG_PPC_CPM_NEW_BINDING |
46 | #include <asm/of_platform.h> | |
47 | #endif | |
48 | ||
48257c4f PA |
49 | #include "fs_enet.h" |
50 | ||
51 | /*************************************************/ | |
52 | ||
976de6a8 | 53 | #ifndef CONFIG_PPC_CPM_NEW_BINDING |
48257c4f PA |
54 | static char version[] __devinitdata = |
55 | DRV_MODULE_NAME ".c:v" DRV_MODULE_VERSION " (" DRV_MODULE_RELDATE ")" "\n"; | |
976de6a8 | 56 | #endif |
48257c4f PA |
57 | |
58 | MODULE_AUTHOR("Pantelis Antoniou <panto@intracom.gr>"); | |
59 | MODULE_DESCRIPTION("Freescale Ethernet Driver"); | |
60 | MODULE_LICENSE("GPL"); | |
61 | MODULE_VERSION(DRV_MODULE_VERSION); | |
62 | ||
31a5bb04 | 63 | static int fs_enet_debug = -1; /* -1 == use FS_ENET_DEF_MSG_ENABLE as value */ |
8d3b33f6 | 64 | module_param(fs_enet_debug, int, 0); |
48257c4f PA |
65 | MODULE_PARM_DESC(fs_enet_debug, |
66 | "Freescale bitmapped debugging message enable value"); | |
67 | ||
9b8ee8e7 VB |
68 | #ifdef CONFIG_NET_POLL_CONTROLLER |
69 | static void fs_enet_netpoll(struct net_device *dev); | |
70 | #endif | |
48257c4f PA |
71 | |
72 | static void fs_set_multicast_list(struct net_device *dev) | |
73 | { | |
74 | struct fs_enet_private *fep = netdev_priv(dev); | |
75 | ||
76 | (*fep->ops->set_multicast_list)(dev); | |
77 | } | |
78 | ||
0d0d9c15 SW |
79 | static void skb_align(struct sk_buff *skb, int align) |
80 | { | |
81 | int off = ((unsigned long)skb->data) & (align - 1); | |
82 | ||
83 | if (off) | |
84 | skb_reserve(skb, align - off); | |
85 | } | |
86 | ||
48257c4f | 87 | /* NAPI receive function */ |
bea3348e | 88 | static int fs_enet_rx_napi(struct napi_struct *napi, int budget) |
48257c4f | 89 | { |
bea3348e SH |
90 | struct fs_enet_private *fep = container_of(napi, struct fs_enet_private, napi); |
91 | struct net_device *dev = to_net_dev(fep->dev); | |
48257c4f | 92 | const struct fs_platform_info *fpi = fep->fpi; |
31a5bb04 | 93 | cbd_t __iomem *bdp; |
48257c4f PA |
94 | struct sk_buff *skb, *skbn, *skbt; |
95 | int received = 0; | |
96 | u16 pkt_len, sc; | |
97 | int curidx; | |
48257c4f PA |
98 | |
99 | if (!netif_running(dev)) | |
100 | return 0; | |
101 | ||
102 | /* | |
103 | * First, grab all of the stats for the incoming packet. | |
104 | * These get messed up if we get called due to a busy condition. | |
105 | */ | |
106 | bdp = fep->cur_rx; | |
107 | ||
108 | /* clear RX status bits for napi*/ | |
109 | (*fep->ops->napi_clear_rx_event)(dev); | |
110 | ||
111 | while (((sc = CBDR_SC(bdp)) & BD_ENET_RX_EMPTY) == 0) { | |
48257c4f PA |
112 | curidx = bdp - fep->rx_bd_base; |
113 | ||
114 | /* | |
115 | * Since we have allocated space to hold a complete frame, | |
116 | * the last indicator should be set. | |
117 | */ | |
118 | if ((sc & BD_ENET_RX_LAST) == 0) | |
119 | printk(KERN_WARNING DRV_MODULE_NAME | |
120 | ": %s rcv is not +last\n", | |
121 | dev->name); | |
122 | ||
123 | /* | |
9b8ee8e7 | 124 | * Check for errors. |
48257c4f PA |
125 | */ |
126 | if (sc & (BD_ENET_RX_LG | BD_ENET_RX_SH | BD_ENET_RX_CL | | |
127 | BD_ENET_RX_NO | BD_ENET_RX_CR | BD_ENET_RX_OV)) { | |
128 | fep->stats.rx_errors++; | |
129 | /* Frame too long or too short. */ | |
130 | if (sc & (BD_ENET_RX_LG | BD_ENET_RX_SH)) | |
131 | fep->stats.rx_length_errors++; | |
132 | /* Frame alignment */ | |
133 | if (sc & (BD_ENET_RX_NO | BD_ENET_RX_CL)) | |
134 | fep->stats.rx_frame_errors++; | |
135 | /* CRC Error */ | |
136 | if (sc & BD_ENET_RX_CR) | |
137 | fep->stats.rx_crc_errors++; | |
138 | /* FIFO overrun */ | |
139 | if (sc & BD_ENET_RX_OV) | |
140 | fep->stats.rx_crc_errors++; | |
141 | ||
142 | skb = fep->rx_skbuff[curidx]; | |
143 | ||
34e30d61 | 144 | dma_unmap_single(fep->dev, CBDR_BUFADDR(bdp), |
48257c4f PA |
145 | L1_CACHE_ALIGN(PKT_MAXBUF_SIZE), |
146 | DMA_FROM_DEVICE); | |
147 | ||
148 | skbn = skb; | |
149 | ||
150 | } else { | |
48257c4f PA |
151 | skb = fep->rx_skbuff[curidx]; |
152 | ||
34e30d61 | 153 | dma_unmap_single(fep->dev, CBDR_BUFADDR(bdp), |
48257c4f PA |
154 | L1_CACHE_ALIGN(PKT_MAXBUF_SIZE), |
155 | DMA_FROM_DEVICE); | |
156 | ||
157 | /* | |
158 | * Process the incoming frame. | |
159 | */ | |
160 | fep->stats.rx_packets++; | |
161 | pkt_len = CBDR_DATLEN(bdp) - 4; /* remove CRC */ | |
162 | fep->stats.rx_bytes += pkt_len + 4; | |
163 | ||
164 | if (pkt_len <= fpi->rx_copybreak) { | |
165 | /* +2 to make IP header L1 cache aligned */ | |
166 | skbn = dev_alloc_skb(pkt_len + 2); | |
167 | if (skbn != NULL) { | |
168 | skb_reserve(skbn, 2); /* align IP header */ | |
d626f62b ACM |
169 | skb_copy_from_linear_data(skb, |
170 | skbn->data, pkt_len); | |
48257c4f PA |
171 | /* swap */ |
172 | skbt = skb; | |
173 | skb = skbn; | |
174 | skbn = skbt; | |
175 | } | |
0d0d9c15 | 176 | } else { |
48257c4f PA |
177 | skbn = dev_alloc_skb(ENET_RX_FRSIZE); |
178 | ||
0d0d9c15 SW |
179 | if (skbn) |
180 | skb_align(skbn, ENET_RX_ALIGN); | |
181 | } | |
182 | ||
48257c4f | 183 | if (skbn != NULL) { |
48257c4f PA |
184 | skb_put(skb, pkt_len); /* Make room */ |
185 | skb->protocol = eth_type_trans(skb, dev); | |
186 | received++; | |
187 | netif_receive_skb(skb); | |
188 | } else { | |
189 | printk(KERN_WARNING DRV_MODULE_NAME | |
190 | ": %s Memory squeeze, dropping packet.\n", | |
191 | dev->name); | |
192 | fep->stats.rx_dropped++; | |
193 | skbn = skb; | |
194 | } | |
195 | } | |
196 | ||
197 | fep->rx_skbuff[curidx] = skbn; | |
198 | CBDW_BUFADDR(bdp, dma_map_single(fep->dev, skbn->data, | |
199 | L1_CACHE_ALIGN(PKT_MAXBUF_SIZE), | |
200 | DMA_FROM_DEVICE)); | |
201 | CBDW_DATLEN(bdp, 0); | |
202 | CBDW_SC(bdp, (sc & ~BD_ENET_RX_STATS) | BD_ENET_RX_EMPTY); | |
203 | ||
204 | /* | |
9b8ee8e7 | 205 | * Update BD pointer to next entry. |
48257c4f PA |
206 | */ |
207 | if ((sc & BD_ENET_RX_WRAP) == 0) | |
208 | bdp++; | |
209 | else | |
210 | bdp = fep->rx_bd_base; | |
211 | ||
212 | (*fep->ops->rx_bd_done)(dev); | |
bea3348e SH |
213 | |
214 | if (received >= budget) | |
215 | break; | |
48257c4f PA |
216 | } |
217 | ||
218 | fep->cur_rx = bdp; | |
219 | ||
bea3348e SH |
220 | if (received >= budget) { |
221 | /* done */ | |
222 | netif_rx_complete(dev, napi); | |
223 | (*fep->ops->napi_enable_rx)(dev); | |
224 | } | |
225 | return received; | |
48257c4f PA |
226 | } |
227 | ||
228 | /* non NAPI receive function */ | |
229 | static int fs_enet_rx_non_napi(struct net_device *dev) | |
230 | { | |
231 | struct fs_enet_private *fep = netdev_priv(dev); | |
232 | const struct fs_platform_info *fpi = fep->fpi; | |
31a5bb04 | 233 | cbd_t __iomem *bdp; |
48257c4f PA |
234 | struct sk_buff *skb, *skbn, *skbt; |
235 | int received = 0; | |
236 | u16 pkt_len, sc; | |
237 | int curidx; | |
238 | /* | |
239 | * First, grab all of the stats for the incoming packet. | |
240 | * These get messed up if we get called due to a busy condition. | |
241 | */ | |
242 | bdp = fep->cur_rx; | |
243 | ||
244 | while (((sc = CBDR_SC(bdp)) & BD_ENET_RX_EMPTY) == 0) { | |
245 | ||
246 | curidx = bdp - fep->rx_bd_base; | |
247 | ||
248 | /* | |
249 | * Since we have allocated space to hold a complete frame, | |
250 | * the last indicator should be set. | |
251 | */ | |
252 | if ((sc & BD_ENET_RX_LAST) == 0) | |
253 | printk(KERN_WARNING DRV_MODULE_NAME | |
254 | ": %s rcv is not +last\n", | |
255 | dev->name); | |
256 | ||
257 | /* | |
9b8ee8e7 | 258 | * Check for errors. |
48257c4f PA |
259 | */ |
260 | if (sc & (BD_ENET_RX_LG | BD_ENET_RX_SH | BD_ENET_RX_CL | | |
261 | BD_ENET_RX_NO | BD_ENET_RX_CR | BD_ENET_RX_OV)) { | |
262 | fep->stats.rx_errors++; | |
263 | /* Frame too long or too short. */ | |
264 | if (sc & (BD_ENET_RX_LG | BD_ENET_RX_SH)) | |
265 | fep->stats.rx_length_errors++; | |
266 | /* Frame alignment */ | |
267 | if (sc & (BD_ENET_RX_NO | BD_ENET_RX_CL)) | |
268 | fep->stats.rx_frame_errors++; | |
269 | /* CRC Error */ | |
270 | if (sc & BD_ENET_RX_CR) | |
271 | fep->stats.rx_crc_errors++; | |
272 | /* FIFO overrun */ | |
273 | if (sc & BD_ENET_RX_OV) | |
274 | fep->stats.rx_crc_errors++; | |
275 | ||
276 | skb = fep->rx_skbuff[curidx]; | |
277 | ||
34e30d61 | 278 | dma_unmap_single(fep->dev, CBDR_BUFADDR(bdp), |
48257c4f PA |
279 | L1_CACHE_ALIGN(PKT_MAXBUF_SIZE), |
280 | DMA_FROM_DEVICE); | |
281 | ||
282 | skbn = skb; | |
283 | ||
284 | } else { | |
285 | ||
286 | skb = fep->rx_skbuff[curidx]; | |
287 | ||
34e30d61 | 288 | dma_unmap_single(fep->dev, CBDR_BUFADDR(bdp), |
48257c4f PA |
289 | L1_CACHE_ALIGN(PKT_MAXBUF_SIZE), |
290 | DMA_FROM_DEVICE); | |
291 | ||
292 | /* | |
293 | * Process the incoming frame. | |
294 | */ | |
295 | fep->stats.rx_packets++; | |
296 | pkt_len = CBDR_DATLEN(bdp) - 4; /* remove CRC */ | |
297 | fep->stats.rx_bytes += pkt_len + 4; | |
298 | ||
299 | if (pkt_len <= fpi->rx_copybreak) { | |
300 | /* +2 to make IP header L1 cache aligned */ | |
301 | skbn = dev_alloc_skb(pkt_len + 2); | |
302 | if (skbn != NULL) { | |
303 | skb_reserve(skbn, 2); /* align IP header */ | |
d626f62b ACM |
304 | skb_copy_from_linear_data(skb, |
305 | skbn->data, pkt_len); | |
48257c4f PA |
306 | /* swap */ |
307 | skbt = skb; | |
308 | skb = skbn; | |
309 | skbn = skbt; | |
310 | } | |
0d0d9c15 | 311 | } else { |
48257c4f PA |
312 | skbn = dev_alloc_skb(ENET_RX_FRSIZE); |
313 | ||
0d0d9c15 SW |
314 | if (skbn) |
315 | skb_align(skbn, ENET_RX_ALIGN); | |
316 | } | |
317 | ||
48257c4f | 318 | if (skbn != NULL) { |
48257c4f PA |
319 | skb_put(skb, pkt_len); /* Make room */ |
320 | skb->protocol = eth_type_trans(skb, dev); | |
321 | received++; | |
322 | netif_rx(skb); | |
323 | } else { | |
324 | printk(KERN_WARNING DRV_MODULE_NAME | |
325 | ": %s Memory squeeze, dropping packet.\n", | |
326 | dev->name); | |
327 | fep->stats.rx_dropped++; | |
328 | skbn = skb; | |
329 | } | |
330 | } | |
331 | ||
332 | fep->rx_skbuff[curidx] = skbn; | |
333 | CBDW_BUFADDR(bdp, dma_map_single(fep->dev, skbn->data, | |
334 | L1_CACHE_ALIGN(PKT_MAXBUF_SIZE), | |
335 | DMA_FROM_DEVICE)); | |
336 | CBDW_DATLEN(bdp, 0); | |
337 | CBDW_SC(bdp, (sc & ~BD_ENET_RX_STATS) | BD_ENET_RX_EMPTY); | |
338 | ||
339 | /* | |
9b8ee8e7 | 340 | * Update BD pointer to next entry. |
48257c4f PA |
341 | */ |
342 | if ((sc & BD_ENET_RX_WRAP) == 0) | |
343 | bdp++; | |
344 | else | |
345 | bdp = fep->rx_bd_base; | |
346 | ||
347 | (*fep->ops->rx_bd_done)(dev); | |
348 | } | |
349 | ||
350 | fep->cur_rx = bdp; | |
351 | ||
352 | return 0; | |
353 | } | |
354 | ||
355 | static void fs_enet_tx(struct net_device *dev) | |
356 | { | |
357 | struct fs_enet_private *fep = netdev_priv(dev); | |
31a5bb04 | 358 | cbd_t __iomem *bdp; |
48257c4f PA |
359 | struct sk_buff *skb; |
360 | int dirtyidx, do_wake, do_restart; | |
361 | u16 sc; | |
362 | ||
aa90f503 | 363 | spin_lock(&fep->tx_lock); |
48257c4f PA |
364 | bdp = fep->dirty_tx; |
365 | ||
366 | do_wake = do_restart = 0; | |
367 | while (((sc = CBDR_SC(bdp)) & BD_ENET_TX_READY) == 0) { | |
48257c4f PA |
368 | dirtyidx = bdp - fep->tx_bd_base; |
369 | ||
370 | if (fep->tx_free == fep->tx_ring) | |
371 | break; | |
372 | ||
373 | skb = fep->tx_skbuff[dirtyidx]; | |
374 | ||
375 | /* | |
9b8ee8e7 | 376 | * Check for errors. |
48257c4f PA |
377 | */ |
378 | if (sc & (BD_ENET_TX_HB | BD_ENET_TX_LC | | |
379 | BD_ENET_TX_RL | BD_ENET_TX_UN | BD_ENET_TX_CSL)) { | |
380 | ||
381 | if (sc & BD_ENET_TX_HB) /* No heartbeat */ | |
382 | fep->stats.tx_heartbeat_errors++; | |
383 | if (sc & BD_ENET_TX_LC) /* Late collision */ | |
384 | fep->stats.tx_window_errors++; | |
385 | if (sc & BD_ENET_TX_RL) /* Retrans limit */ | |
386 | fep->stats.tx_aborted_errors++; | |
387 | if (sc & BD_ENET_TX_UN) /* Underrun */ | |
388 | fep->stats.tx_fifo_errors++; | |
389 | if (sc & BD_ENET_TX_CSL) /* Carrier lost */ | |
390 | fep->stats.tx_carrier_errors++; | |
391 | ||
392 | if (sc & (BD_ENET_TX_LC | BD_ENET_TX_RL | BD_ENET_TX_UN)) { | |
393 | fep->stats.tx_errors++; | |
394 | do_restart = 1; | |
395 | } | |
396 | } else | |
397 | fep->stats.tx_packets++; | |
398 | ||
399 | if (sc & BD_ENET_TX_READY) | |
400 | printk(KERN_WARNING DRV_MODULE_NAME | |
401 | ": %s HEY! Enet xmit interrupt and TX_READY.\n", | |
402 | dev->name); | |
403 | ||
404 | /* | |
405 | * Deferred means some collisions occurred during transmit, | |
406 | * but we eventually sent the packet OK. | |
407 | */ | |
408 | if (sc & BD_ENET_TX_DEF) | |
409 | fep->stats.collisions++; | |
410 | ||
411 | /* unmap */ | |
34e30d61 PA |
412 | dma_unmap_single(fep->dev, CBDR_BUFADDR(bdp), |
413 | skb->len, DMA_TO_DEVICE); | |
48257c4f PA |
414 | |
415 | /* | |
9b8ee8e7 | 416 | * Free the sk buffer associated with this last transmit. |
48257c4f PA |
417 | */ |
418 | dev_kfree_skb_irq(skb); | |
419 | fep->tx_skbuff[dirtyidx] = NULL; | |
420 | ||
421 | /* | |
9b8ee8e7 | 422 | * Update pointer to next buffer descriptor to be transmitted. |
48257c4f PA |
423 | */ |
424 | if ((sc & BD_ENET_TX_WRAP) == 0) | |
425 | bdp++; | |
426 | else | |
427 | bdp = fep->tx_bd_base; | |
428 | ||
429 | /* | |
430 | * Since we have freed up a buffer, the ring is no longer | |
431 | * full. | |
432 | */ | |
433 | if (!fep->tx_free++) | |
434 | do_wake = 1; | |
435 | } | |
436 | ||
437 | fep->dirty_tx = bdp; | |
438 | ||
439 | if (do_restart) | |
440 | (*fep->ops->tx_restart)(dev); | |
441 | ||
aa90f503 | 442 | spin_unlock(&fep->tx_lock); |
48257c4f PA |
443 | |
444 | if (do_wake) | |
445 | netif_wake_queue(dev); | |
446 | } | |
447 | ||
448 | /* | |
449 | * The interrupt handler. | |
450 | * This is called from the MPC core interrupt. | |
451 | */ | |
452 | static irqreturn_t | |
7d12e780 | 453 | fs_enet_interrupt(int irq, void *dev_id) |
48257c4f PA |
454 | { |
455 | struct net_device *dev = dev_id; | |
456 | struct fs_enet_private *fep; | |
457 | const struct fs_platform_info *fpi; | |
458 | u32 int_events; | |
459 | u32 int_clr_events; | |
460 | int nr, napi_ok; | |
461 | int handled; | |
462 | ||
463 | fep = netdev_priv(dev); | |
464 | fpi = fep->fpi; | |
465 | ||
466 | nr = 0; | |
467 | while ((int_events = (*fep->ops->get_int_events)(dev)) != 0) { | |
48257c4f PA |
468 | nr++; |
469 | ||
470 | int_clr_events = int_events; | |
471 | if (fpi->use_napi) | |
472 | int_clr_events &= ~fep->ev_napi_rx; | |
473 | ||
474 | (*fep->ops->clear_int_events)(dev, int_clr_events); | |
475 | ||
476 | if (int_events & fep->ev_err) | |
477 | (*fep->ops->ev_error)(dev, int_events); | |
478 | ||
479 | if (int_events & fep->ev_rx) { | |
480 | if (!fpi->use_napi) | |
481 | fs_enet_rx_non_napi(dev); | |
482 | else { | |
bea3348e | 483 | napi_ok = napi_schedule_prep(&fep->napi); |
48257c4f PA |
484 | |
485 | (*fep->ops->napi_disable_rx)(dev); | |
486 | (*fep->ops->clear_int_events)(dev, fep->ev_napi_rx); | |
487 | ||
488 | /* NOTE: it is possible for FCCs in NAPI mode */ | |
489 | /* to submit a spurious interrupt while in poll */ | |
490 | if (napi_ok) | |
bea3348e | 491 | __netif_rx_schedule(dev, &fep->napi); |
48257c4f PA |
492 | } |
493 | } | |
494 | ||
495 | if (int_events & fep->ev_tx) | |
496 | fs_enet_tx(dev); | |
497 | } | |
498 | ||
499 | handled = nr > 0; | |
500 | return IRQ_RETVAL(handled); | |
501 | } | |
502 | ||
503 | void fs_init_bds(struct net_device *dev) | |
504 | { | |
505 | struct fs_enet_private *fep = netdev_priv(dev); | |
31a5bb04 | 506 | cbd_t __iomem *bdp; |
48257c4f PA |
507 | struct sk_buff *skb; |
508 | int i; | |
509 | ||
510 | fs_cleanup_bds(dev); | |
511 | ||
512 | fep->dirty_tx = fep->cur_tx = fep->tx_bd_base; | |
513 | fep->tx_free = fep->tx_ring; | |
514 | fep->cur_rx = fep->rx_bd_base; | |
515 | ||
516 | /* | |
9b8ee8e7 | 517 | * Initialize the receive buffer descriptors. |
48257c4f PA |
518 | */ |
519 | for (i = 0, bdp = fep->rx_bd_base; i < fep->rx_ring; i++, bdp++) { | |
520 | skb = dev_alloc_skb(ENET_RX_FRSIZE); | |
521 | if (skb == NULL) { | |
522 | printk(KERN_WARNING DRV_MODULE_NAME | |
523 | ": %s Memory squeeze, unable to allocate skb\n", | |
524 | dev->name); | |
525 | break; | |
526 | } | |
0d0d9c15 | 527 | skb_align(skb, ENET_RX_ALIGN); |
48257c4f | 528 | fep->rx_skbuff[i] = skb; |
48257c4f PA |
529 | CBDW_BUFADDR(bdp, |
530 | dma_map_single(fep->dev, skb->data, | |
531 | L1_CACHE_ALIGN(PKT_MAXBUF_SIZE), | |
532 | DMA_FROM_DEVICE)); | |
533 | CBDW_DATLEN(bdp, 0); /* zero */ | |
534 | CBDW_SC(bdp, BD_ENET_RX_EMPTY | | |
535 | ((i < fep->rx_ring - 1) ? 0 : BD_SC_WRAP)); | |
536 | } | |
537 | /* | |
9b8ee8e7 | 538 | * if we failed, fillup remainder |
48257c4f PA |
539 | */ |
540 | for (; i < fep->rx_ring; i++, bdp++) { | |
541 | fep->rx_skbuff[i] = NULL; | |
542 | CBDW_SC(bdp, (i < fep->rx_ring - 1) ? 0 : BD_SC_WRAP); | |
543 | } | |
544 | ||
545 | /* | |
9b8ee8e7 | 546 | * ...and the same for transmit. |
48257c4f PA |
547 | */ |
548 | for (i = 0, bdp = fep->tx_bd_base; i < fep->tx_ring; i++, bdp++) { | |
549 | fep->tx_skbuff[i] = NULL; | |
550 | CBDW_BUFADDR(bdp, 0); | |
551 | CBDW_DATLEN(bdp, 0); | |
552 | CBDW_SC(bdp, (i < fep->tx_ring - 1) ? 0 : BD_SC_WRAP); | |
553 | } | |
554 | } | |
555 | ||
556 | void fs_cleanup_bds(struct net_device *dev) | |
557 | { | |
558 | struct fs_enet_private *fep = netdev_priv(dev); | |
559 | struct sk_buff *skb; | |
31a5bb04 | 560 | cbd_t __iomem *bdp; |
48257c4f PA |
561 | int i; |
562 | ||
563 | /* | |
9b8ee8e7 | 564 | * Reset SKB transmit buffers. |
48257c4f | 565 | */ |
34e30d61 | 566 | for (i = 0, bdp = fep->tx_bd_base; i < fep->tx_ring; i++, bdp++) { |
48257c4f PA |
567 | if ((skb = fep->tx_skbuff[i]) == NULL) |
568 | continue; | |
569 | ||
570 | /* unmap */ | |
34e30d61 PA |
571 | dma_unmap_single(fep->dev, CBDR_BUFADDR(bdp), |
572 | skb->len, DMA_TO_DEVICE); | |
48257c4f PA |
573 | |
574 | fep->tx_skbuff[i] = NULL; | |
575 | dev_kfree_skb(skb); | |
576 | } | |
577 | ||
578 | /* | |
9b8ee8e7 | 579 | * Reset SKB receive buffers |
48257c4f | 580 | */ |
34e30d61 | 581 | for (i = 0, bdp = fep->rx_bd_base; i < fep->rx_ring; i++, bdp++) { |
48257c4f PA |
582 | if ((skb = fep->rx_skbuff[i]) == NULL) |
583 | continue; | |
584 | ||
585 | /* unmap */ | |
34e30d61 | 586 | dma_unmap_single(fep->dev, CBDR_BUFADDR(bdp), |
48257c4f PA |
587 | L1_CACHE_ALIGN(PKT_MAXBUF_SIZE), |
588 | DMA_FROM_DEVICE); | |
589 | ||
590 | fep->rx_skbuff[i] = NULL; | |
591 | ||
592 | dev_kfree_skb(skb); | |
593 | } | |
594 | } | |
595 | ||
596 | /**********************************************************************************/ | |
597 | ||
598 | static int fs_enet_start_xmit(struct sk_buff *skb, struct net_device *dev) | |
599 | { | |
600 | struct fs_enet_private *fep = netdev_priv(dev); | |
31a5bb04 | 601 | cbd_t __iomem *bdp; |
48257c4f PA |
602 | int curidx; |
603 | u16 sc; | |
604 | unsigned long flags; | |
605 | ||
606 | spin_lock_irqsave(&fep->tx_lock, flags); | |
607 | ||
608 | /* | |
9b8ee8e7 | 609 | * Fill in a Tx ring entry |
48257c4f PA |
610 | */ |
611 | bdp = fep->cur_tx; | |
612 | ||
613 | if (!fep->tx_free || (CBDR_SC(bdp) & BD_ENET_TX_READY)) { | |
614 | netif_stop_queue(dev); | |
615 | spin_unlock_irqrestore(&fep->tx_lock, flags); | |
616 | ||
617 | /* | |
618 | * Ooops. All transmit buffers are full. Bail out. | |
619 | * This should not happen, since the tx queue should be stopped. | |
620 | */ | |
621 | printk(KERN_WARNING DRV_MODULE_NAME | |
622 | ": %s tx queue full!.\n", dev->name); | |
623 | return NETDEV_TX_BUSY; | |
624 | } | |
625 | ||
626 | curidx = bdp - fep->tx_bd_base; | |
627 | /* | |
9b8ee8e7 | 628 | * Clear all of the status flags. |
48257c4f PA |
629 | */ |
630 | CBDC_SC(bdp, BD_ENET_TX_STATS); | |
631 | ||
632 | /* | |
9b8ee8e7 | 633 | * Save skb pointer. |
48257c4f PA |
634 | */ |
635 | fep->tx_skbuff[curidx] = skb; | |
636 | ||
637 | fep->stats.tx_bytes += skb->len; | |
638 | ||
639 | /* | |
9b8ee8e7 | 640 | * Push the data cache so the CPM does not get stale memory data. |
48257c4f PA |
641 | */ |
642 | CBDW_BUFADDR(bdp, dma_map_single(fep->dev, | |
643 | skb->data, skb->len, DMA_TO_DEVICE)); | |
644 | CBDW_DATLEN(bdp, skb->len); | |
645 | ||
646 | dev->trans_start = jiffies; | |
647 | ||
648 | /* | |
9b8ee8e7 | 649 | * If this was the last BD in the ring, start at the beginning again. |
48257c4f PA |
650 | */ |
651 | if ((CBDR_SC(bdp) & BD_ENET_TX_WRAP) == 0) | |
652 | fep->cur_tx++; | |
653 | else | |
654 | fep->cur_tx = fep->tx_bd_base; | |
655 | ||
656 | if (!--fep->tx_free) | |
657 | netif_stop_queue(dev); | |
658 | ||
659 | /* Trigger transmission start */ | |
660 | sc = BD_ENET_TX_READY | BD_ENET_TX_INTR | | |
661 | BD_ENET_TX_LAST | BD_ENET_TX_TC; | |
662 | ||
663 | /* note that while FEC does not have this bit | |
664 | * it marks it as available for software use | |
665 | * yay for hw reuse :) */ | |
666 | if (skb->len <= 60) | |
667 | sc |= BD_ENET_TX_PAD; | |
668 | CBDS_SC(bdp, sc); | |
669 | ||
670 | (*fep->ops->tx_kickstart)(dev); | |
671 | ||
672 | spin_unlock_irqrestore(&fep->tx_lock, flags); | |
673 | ||
674 | return NETDEV_TX_OK; | |
675 | } | |
676 | ||
677 | static int fs_request_irq(struct net_device *dev, int irq, const char *name, | |
7d12e780 | 678 | irq_handler_t irqf) |
48257c4f PA |
679 | { |
680 | struct fs_enet_private *fep = netdev_priv(dev); | |
681 | ||
682 | (*fep->ops->pre_request_irq)(dev, irq); | |
1fb9df5d | 683 | return request_irq(irq, irqf, IRQF_SHARED, name, dev); |
48257c4f PA |
684 | } |
685 | ||
686 | static void fs_free_irq(struct net_device *dev, int irq) | |
687 | { | |
688 | struct fs_enet_private *fep = netdev_priv(dev); | |
689 | ||
690 | free_irq(irq, dev); | |
691 | (*fep->ops->post_free_irq)(dev, irq); | |
692 | } | |
693 | ||
48257c4f PA |
694 | static void fs_timeout(struct net_device *dev) |
695 | { | |
696 | struct fs_enet_private *fep = netdev_priv(dev); | |
697 | unsigned long flags; | |
698 | int wake = 0; | |
699 | ||
700 | fep->stats.tx_errors++; | |
701 | ||
702 | spin_lock_irqsave(&fep->lock, flags); | |
703 | ||
704 | if (dev->flags & IFF_UP) { | |
5b4b8454 | 705 | phy_stop(fep->phydev); |
48257c4f PA |
706 | (*fep->ops->stop)(dev); |
707 | (*fep->ops->restart)(dev); | |
5b4b8454 | 708 | phy_start(fep->phydev); |
48257c4f PA |
709 | } |
710 | ||
5b4b8454 | 711 | phy_start(fep->phydev); |
48257c4f PA |
712 | wake = fep->tx_free && !(CBDR_SC(fep->cur_tx) & BD_ENET_TX_READY); |
713 | spin_unlock_irqrestore(&fep->lock, flags); | |
714 | ||
715 | if (wake) | |
716 | netif_wake_queue(dev); | |
717 | } | |
718 | ||
5b4b8454 VB |
719 | /*----------------------------------------------------------------------------- |
720 | * generic link-change handler - should be sufficient for most cases | |
721 | *-----------------------------------------------------------------------------*/ | |
722 | static void generic_adjust_link(struct net_device *dev) | |
723 | { | |
0fb300fa SW |
724 | struct fs_enet_private *fep = netdev_priv(dev); |
725 | struct phy_device *phydev = fep->phydev; | |
726 | int new_state = 0; | |
727 | ||
728 | if (phydev->link) { | |
729 | /* adjust to duplex mode */ | |
730 | if (phydev->duplex != fep->oldduplex) { | |
731 | new_state = 1; | |
732 | fep->oldduplex = phydev->duplex; | |
733 | } | |
734 | ||
735 | if (phydev->speed != fep->oldspeed) { | |
736 | new_state = 1; | |
737 | fep->oldspeed = phydev->speed; | |
738 | } | |
739 | ||
740 | if (!fep->oldlink) { | |
741 | new_state = 1; | |
742 | fep->oldlink = 1; | |
743 | netif_schedule(dev); | |
744 | netif_carrier_on(dev); | |
745 | netif_start_queue(dev); | |
746 | } | |
747 | ||
748 | if (new_state) | |
749 | fep->ops->restart(dev); | |
750 | } else if (fep->oldlink) { | |
751 | new_state = 1; | |
752 | fep->oldlink = 0; | |
753 | fep->oldspeed = 0; | |
754 | fep->oldduplex = -1; | |
755 | netif_carrier_off(dev); | |
756 | netif_stop_queue(dev); | |
757 | } | |
758 | ||
759 | if (new_state && netif_msg_link(fep)) | |
760 | phy_print_status(phydev); | |
5b4b8454 VB |
761 | } |
762 | ||
763 | ||
764 | static void fs_adjust_link(struct net_device *dev) | |
765 | { | |
766 | struct fs_enet_private *fep = netdev_priv(dev); | |
767 | unsigned long flags; | |
768 | ||
769 | spin_lock_irqsave(&fep->lock, flags); | |
770 | ||
771 | if(fep->ops->adjust_link) | |
772 | fep->ops->adjust_link(dev); | |
773 | else | |
774 | generic_adjust_link(dev); | |
775 | ||
776 | spin_unlock_irqrestore(&fep->lock, flags); | |
777 | } | |
778 | ||
779 | static int fs_init_phy(struct net_device *dev) | |
780 | { | |
781 | struct fs_enet_private *fep = netdev_priv(dev); | |
782 | struct phy_device *phydev; | |
783 | ||
784 | fep->oldlink = 0; | |
785 | fep->oldspeed = 0; | |
786 | fep->oldduplex = -1; | |
787 | if(fep->fpi->bus_id) | |
e8a2b6a4 AF |
788 | phydev = phy_connect(dev, fep->fpi->bus_id, &fs_adjust_link, 0, |
789 | PHY_INTERFACE_MODE_MII); | |
5b4b8454 VB |
790 | else { |
791 | printk("No phy bus ID specified in BSP code\n"); | |
792 | return -EINVAL; | |
793 | } | |
794 | if (IS_ERR(phydev)) { | |
795 | printk(KERN_ERR "%s: Could not attach to PHY\n", dev->name); | |
796 | return PTR_ERR(phydev); | |
797 | } | |
798 | ||
799 | fep->phydev = phydev; | |
800 | ||
801 | return 0; | |
802 | } | |
803 | ||
48257c4f PA |
804 | static int fs_enet_open(struct net_device *dev) |
805 | { | |
806 | struct fs_enet_private *fep = netdev_priv(dev); | |
48257c4f | 807 | int r; |
5b4b8454 | 808 | int err; |
48257c4f | 809 | |
bea3348e SH |
810 | napi_enable(&fep->napi); |
811 | ||
48257c4f PA |
812 | /* Install our interrupt handler. */ |
813 | r = fs_request_irq(dev, fep->interrupt, "fs_enet-mac", fs_enet_interrupt); | |
814 | if (r != 0) { | |
815 | printk(KERN_ERR DRV_MODULE_NAME | |
5b4b8454 | 816 | ": %s Could not allocate FS_ENET IRQ!", dev->name); |
bea3348e | 817 | napi_disable(&fep->napi); |
48257c4f PA |
818 | return -EINVAL; |
819 | } | |
820 | ||
5b4b8454 | 821 | err = fs_init_phy(dev); |
bea3348e SH |
822 | if(err) { |
823 | napi_disable(&fep->napi); | |
5b4b8454 | 824 | return err; |
bea3348e | 825 | } |
5b4b8454 | 826 | phy_start(fep->phydev); |
48257c4f PA |
827 | |
828 | return 0; | |
829 | } | |
830 | ||
831 | static int fs_enet_close(struct net_device *dev) | |
832 | { | |
833 | struct fs_enet_private *fep = netdev_priv(dev); | |
48257c4f PA |
834 | unsigned long flags; |
835 | ||
836 | netif_stop_queue(dev); | |
837 | netif_carrier_off(dev); | |
bea3348e | 838 | napi_disable(&fep->napi); |
5b4b8454 | 839 | phy_stop(fep->phydev); |
48257c4f PA |
840 | |
841 | spin_lock_irqsave(&fep->lock, flags); | |
aa90f503 | 842 | spin_lock(&fep->tx_lock); |
48257c4f | 843 | (*fep->ops->stop)(dev); |
aa90f503 | 844 | spin_unlock(&fep->tx_lock); |
48257c4f PA |
845 | spin_unlock_irqrestore(&fep->lock, flags); |
846 | ||
847 | /* release any irqs */ | |
5b4b8454 VB |
848 | phy_disconnect(fep->phydev); |
849 | fep->phydev = NULL; | |
48257c4f PA |
850 | fs_free_irq(dev, fep->interrupt); |
851 | ||
852 | return 0; | |
853 | } | |
854 | ||
855 | static struct net_device_stats *fs_enet_get_stats(struct net_device *dev) | |
856 | { | |
857 | struct fs_enet_private *fep = netdev_priv(dev); | |
858 | return &fep->stats; | |
859 | } | |
860 | ||
861 | /*************************************************************************/ | |
862 | ||
863 | static void fs_get_drvinfo(struct net_device *dev, | |
864 | struct ethtool_drvinfo *info) | |
865 | { | |
866 | strcpy(info->driver, DRV_MODULE_NAME); | |
867 | strcpy(info->version, DRV_MODULE_VERSION); | |
868 | } | |
869 | ||
870 | static int fs_get_regs_len(struct net_device *dev) | |
871 | { | |
872 | struct fs_enet_private *fep = netdev_priv(dev); | |
873 | ||
874 | return (*fep->ops->get_regs_len)(dev); | |
875 | } | |
876 | ||
877 | static void fs_get_regs(struct net_device *dev, struct ethtool_regs *regs, | |
878 | void *p) | |
879 | { | |
880 | struct fs_enet_private *fep = netdev_priv(dev); | |
881 | unsigned long flags; | |
882 | int r, len; | |
883 | ||
884 | len = regs->len; | |
885 | ||
886 | spin_lock_irqsave(&fep->lock, flags); | |
887 | r = (*fep->ops->get_regs)(dev, p, &len); | |
888 | spin_unlock_irqrestore(&fep->lock, flags); | |
889 | ||
890 | if (r == 0) | |
891 | regs->version = 0; | |
892 | } | |
893 | ||
894 | static int fs_get_settings(struct net_device *dev, struct ethtool_cmd *cmd) | |
895 | { | |
896 | struct fs_enet_private *fep = netdev_priv(dev); | |
5b4b8454 | 897 | return phy_ethtool_gset(fep->phydev, cmd); |
48257c4f PA |
898 | } |
899 | ||
900 | static int fs_set_settings(struct net_device *dev, struct ethtool_cmd *cmd) | |
901 | { | |
902 | struct fs_enet_private *fep = netdev_priv(dev); | |
5b4b8454 VB |
903 | phy_ethtool_sset(fep->phydev, cmd); |
904 | return 0; | |
48257c4f PA |
905 | } |
906 | ||
907 | static int fs_nway_reset(struct net_device *dev) | |
908 | { | |
5b4b8454 | 909 | return 0; |
48257c4f PA |
910 | } |
911 | ||
912 | static u32 fs_get_msglevel(struct net_device *dev) | |
913 | { | |
914 | struct fs_enet_private *fep = netdev_priv(dev); | |
915 | return fep->msg_enable; | |
916 | } | |
917 | ||
918 | static void fs_set_msglevel(struct net_device *dev, u32 value) | |
919 | { | |
920 | struct fs_enet_private *fep = netdev_priv(dev); | |
921 | fep->msg_enable = value; | |
922 | } | |
923 | ||
7282d491 | 924 | static const struct ethtool_ops fs_ethtool_ops = { |
48257c4f PA |
925 | .get_drvinfo = fs_get_drvinfo, |
926 | .get_regs_len = fs_get_regs_len, | |
927 | .get_settings = fs_get_settings, | |
928 | .set_settings = fs_set_settings, | |
929 | .nway_reset = fs_nway_reset, | |
930 | .get_link = ethtool_op_get_link, | |
931 | .get_msglevel = fs_get_msglevel, | |
932 | .set_msglevel = fs_set_msglevel, | |
48257c4f | 933 | .set_tx_csum = ethtool_op_set_tx_csum, /* local! */ |
48257c4f PA |
934 | .set_sg = ethtool_op_set_sg, |
935 | .get_regs = fs_get_regs, | |
936 | }; | |
937 | ||
938 | static int fs_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) | |
939 | { | |
940 | struct fs_enet_private *fep = netdev_priv(dev); | |
941 | struct mii_ioctl_data *mii = (struct mii_ioctl_data *)&rq->ifr_data; | |
942 | unsigned long flags; | |
943 | int rc; | |
944 | ||
945 | if (!netif_running(dev)) | |
946 | return -EINVAL; | |
947 | ||
948 | spin_lock_irqsave(&fep->lock, flags); | |
5b4b8454 | 949 | rc = phy_mii_ioctl(fep->phydev, mii, cmd); |
48257c4f PA |
950 | spin_unlock_irqrestore(&fep->lock, flags); |
951 | return rc; | |
952 | } | |
953 | ||
954 | extern int fs_mii_connect(struct net_device *dev); | |
955 | extern void fs_mii_disconnect(struct net_device *dev); | |
956 | ||
976de6a8 | 957 | #ifndef CONFIG_PPC_CPM_NEW_BINDING |
48257c4f | 958 | static struct net_device *fs_init_instance(struct device *dev, |
611a15af | 959 | struct fs_platform_info *fpi) |
48257c4f PA |
960 | { |
961 | struct net_device *ndev = NULL; | |
962 | struct fs_enet_private *fep = NULL; | |
963 | int privsize, i, r, err = 0, registered = 0; | |
964 | ||
611a15af | 965 | fpi->fs_no = fs_get_id(fpi); |
48257c4f PA |
966 | /* guard */ |
967 | if ((unsigned int)fpi->fs_no >= FS_MAX_INDEX) | |
968 | return ERR_PTR(-EINVAL); | |
969 | ||
970 | privsize = sizeof(*fep) + (sizeof(struct sk_buff **) * | |
971 | (fpi->rx_ring + fpi->tx_ring)); | |
972 | ||
973 | ndev = alloc_etherdev(privsize); | |
974 | if (!ndev) { | |
975 | err = -ENOMEM; | |
976 | goto err; | |
977 | } | |
48257c4f PA |
978 | |
979 | fep = netdev_priv(ndev); | |
48257c4f PA |
980 | |
981 | fep->dev = dev; | |
982 | dev_set_drvdata(dev, ndev); | |
983 | fep->fpi = fpi; | |
984 | if (fpi->init_ioports) | |
d3465c92 | 985 | fpi->init_ioports((struct fs_platform_info *)fpi); |
48257c4f PA |
986 | |
987 | #ifdef CONFIG_FS_ENET_HAS_FEC | |
988 | if (fs_get_fec_index(fpi->fs_no) >= 0) | |
989 | fep->ops = &fs_fec_ops; | |
990 | #endif | |
991 | ||
992 | #ifdef CONFIG_FS_ENET_HAS_SCC | |
0fb300fa | 993 | if (fs_get_scc_index(fpi->fs_no) >=0) |
48257c4f PA |
994 | fep->ops = &fs_scc_ops; |
995 | #endif | |
996 | ||
997 | #ifdef CONFIG_FS_ENET_HAS_FCC | |
998 | if (fs_get_fcc_index(fpi->fs_no) >= 0) | |
999 | fep->ops = &fs_fcc_ops; | |
1000 | #endif | |
1001 | ||
1002 | if (fep->ops == NULL) { | |
1003 | printk(KERN_ERR DRV_MODULE_NAME | |
1004 | ": %s No matching ops found (%d).\n", | |
1005 | ndev->name, fpi->fs_no); | |
1006 | err = -EINVAL; | |
1007 | goto err; | |
1008 | } | |
1009 | ||
1010 | r = (*fep->ops->setup_data)(ndev); | |
1011 | if (r != 0) { | |
1012 | printk(KERN_ERR DRV_MODULE_NAME | |
1013 | ": %s setup_data failed\n", | |
1014 | ndev->name); | |
1015 | err = r; | |
1016 | goto err; | |
1017 | } | |
1018 | ||
1019 | /* point rx_skbuff, tx_skbuff */ | |
1020 | fep->rx_skbuff = (struct sk_buff **)&fep[1]; | |
1021 | fep->tx_skbuff = fep->rx_skbuff + fpi->rx_ring; | |
1022 | ||
1023 | /* init locks */ | |
1024 | spin_lock_init(&fep->lock); | |
1025 | spin_lock_init(&fep->tx_lock); | |
1026 | ||
1027 | /* | |
9b8ee8e7 | 1028 | * Set the Ethernet address. |
48257c4f PA |
1029 | */ |
1030 | for (i = 0; i < 6; i++) | |
1031 | ndev->dev_addr[i] = fpi->macaddr[i]; | |
9b8ee8e7 | 1032 | |
48257c4f | 1033 | r = (*fep->ops->allocate_bd)(ndev); |
9b8ee8e7 | 1034 | |
48257c4f PA |
1035 | if (fep->ring_base == NULL) { |
1036 | printk(KERN_ERR DRV_MODULE_NAME | |
1037 | ": %s buffer descriptor alloc failed (%d).\n", ndev->name, r); | |
1038 | err = r; | |
1039 | goto err; | |
1040 | } | |
1041 | ||
1042 | /* | |
1043 | * Set receive and transmit descriptor base. | |
1044 | */ | |
1045 | fep->rx_bd_base = fep->ring_base; | |
1046 | fep->tx_bd_base = fep->rx_bd_base + fpi->rx_ring; | |
1047 | ||
1048 | /* initialize ring size variables */ | |
1049 | fep->tx_ring = fpi->tx_ring; | |
1050 | fep->rx_ring = fpi->rx_ring; | |
1051 | ||
1052 | /* | |
9b8ee8e7 | 1053 | * The FEC Ethernet specific entries in the device structure. |
48257c4f PA |
1054 | */ |
1055 | ndev->open = fs_enet_open; | |
1056 | ndev->hard_start_xmit = fs_enet_start_xmit; | |
1057 | ndev->tx_timeout = fs_timeout; | |
1058 | ndev->watchdog_timeo = 2 * HZ; | |
1059 | ndev->stop = fs_enet_close; | |
1060 | ndev->get_stats = fs_enet_get_stats; | |
1061 | ndev->set_multicast_list = fs_set_multicast_list; | |
9b8ee8e7 VB |
1062 | |
1063 | #ifdef CONFIG_NET_POLL_CONTROLLER | |
1064 | ndev->poll_controller = fs_enet_netpoll; | |
1065 | #endif | |
1066 | ||
bea3348e SH |
1067 | netif_napi_add(ndev, &fep->napi, |
1068 | fs_enet_rx_napi, fpi->napi_weight); | |
1069 | ||
48257c4f PA |
1070 | ndev->ethtool_ops = &fs_ethtool_ops; |
1071 | ndev->do_ioctl = fs_ioctl; | |
1072 | ||
1073 | init_timer(&fep->phy_timer_list); | |
1074 | ||
1075 | netif_carrier_off(ndev); | |
1076 | ||
1077 | err = register_netdev(ndev); | |
1078 | if (err != 0) { | |
1079 | printk(KERN_ERR DRV_MODULE_NAME | |
1080 | ": %s register_netdev failed.\n", ndev->name); | |
1081 | goto err; | |
1082 | } | |
1083 | registered = 1; | |
1084 | ||
48257c4f PA |
1085 | |
1086 | return ndev; | |
1087 | ||
0fb300fa | 1088 | err: |
48257c4f | 1089 | if (ndev != NULL) { |
48257c4f PA |
1090 | if (registered) |
1091 | unregister_netdev(ndev); | |
1092 | ||
1093 | if (fep != NULL) { | |
1094 | (*fep->ops->free_bd)(ndev); | |
1095 | (*fep->ops->cleanup_data)(ndev); | |
1096 | } | |
1097 | ||
1098 | free_netdev(ndev); | |
1099 | } | |
1100 | ||
1101 | dev_set_drvdata(dev, NULL); | |
1102 | ||
1103 | return ERR_PTR(err); | |
1104 | } | |
1105 | ||
1106 | static int fs_cleanup_instance(struct net_device *ndev) | |
1107 | { | |
1108 | struct fs_enet_private *fep; | |
1109 | const struct fs_platform_info *fpi; | |
1110 | struct device *dev; | |
1111 | ||
1112 | if (ndev == NULL) | |
1113 | return -EINVAL; | |
1114 | ||
1115 | fep = netdev_priv(ndev); | |
1116 | if (fep == NULL) | |
1117 | return -EINVAL; | |
1118 | ||
1119 | fpi = fep->fpi; | |
1120 | ||
48257c4f PA |
1121 | unregister_netdev(ndev); |
1122 | ||
1123 | dma_free_coherent(fep->dev, (fpi->tx_ring + fpi->rx_ring) * sizeof(cbd_t), | |
31a5bb04 | 1124 | (void __force *)fep->ring_base, fep->ring_mem_addr); |
48257c4f PA |
1125 | |
1126 | /* reset it */ | |
1127 | (*fep->ops->cleanup_data)(ndev); | |
1128 | ||
1129 | dev = fep->dev; | |
1130 | if (dev != NULL) { | |
1131 | dev_set_drvdata(dev, NULL); | |
1132 | fep->dev = NULL; | |
1133 | } | |
1134 | ||
1135 | free_netdev(ndev); | |
1136 | ||
1137 | return 0; | |
1138 | } | |
976de6a8 | 1139 | #endif |
48257c4f PA |
1140 | |
1141 | /**************************************************************************************/ | |
1142 | ||
1143 | /* handy pointer to the immap */ | |
31a5bb04 | 1144 | void __iomem *fs_enet_immap = NULL; |
48257c4f PA |
1145 | |
1146 | static int setup_immap(void) | |
1147 | { | |
48257c4f | 1148 | #ifdef CONFIG_CPM1 |
976de6a8 SW |
1149 | fs_enet_immap = ioremap(IMAP_ADDR, 0x4000); |
1150 | WARN_ON(!fs_enet_immap); | |
1151 | #elif defined(CONFIG_CPM2) | |
1152 | fs_enet_immap = cpm2_immr; | |
48257c4f | 1153 | #endif |
48257c4f PA |
1154 | |
1155 | return 0; | |
1156 | } | |
1157 | ||
1158 | static void cleanup_immap(void) | |
1159 | { | |
976de6a8 SW |
1160 | #if defined(CONFIG_CPM1) |
1161 | iounmap(fs_enet_immap); | |
1162 | #endif | |
48257c4f PA |
1163 | } |
1164 | ||
1165 | /**************************************************************************************/ | |
1166 | ||
976de6a8 SW |
1167 | #ifdef CONFIG_PPC_CPM_NEW_BINDING |
1168 | static int __devinit find_phy(struct device_node *np, | |
1169 | struct fs_platform_info *fpi) | |
1170 | { | |
1171 | struct device_node *phynode, *mdionode; | |
1172 | struct resource res; | |
1173 | int ret = 0, len; | |
1174 | ||
1175 | const u32 *data = of_get_property(np, "phy-handle", &len); | |
1176 | if (!data || len != 4) | |
1177 | return -EINVAL; | |
1178 | ||
1179 | phynode = of_find_node_by_phandle(*data); | |
1180 | if (!phynode) | |
1181 | return -EINVAL; | |
1182 | ||
1183 | mdionode = of_get_parent(phynode); | |
1184 | if (!mdionode) | |
1185 | goto out_put_phy; | |
1186 | ||
1187 | ret = of_address_to_resource(mdionode, 0, &res); | |
1188 | if (ret) | |
1189 | goto out_put_mdio; | |
1190 | ||
1191 | data = of_get_property(phynode, "reg", &len); | |
1192 | if (!data || len != 4) | |
1193 | goto out_put_mdio; | |
1194 | ||
1195 | snprintf(fpi->bus_id, 16, PHY_ID_FMT, res.start, *data); | |
1196 | ||
1197 | out_put_mdio: | |
1198 | of_node_put(mdionode); | |
1199 | out_put_phy: | |
1200 | of_node_put(phynode); | |
1201 | return ret; | |
1202 | } | |
1203 | ||
1204 | #ifdef CONFIG_FS_ENET_HAS_FEC | |
1205 | #define IS_FEC(match) ((match)->data == &fs_fec_ops) | |
1206 | #else | |
1207 | #define IS_FEC(match) 0 | |
1208 | #endif | |
1209 | ||
1210 | static int __devinit fs_enet_probe(struct of_device *ofdev, | |
1211 | const struct of_device_id *match) | |
1212 | { | |
1213 | struct net_device *ndev; | |
1214 | struct fs_enet_private *fep; | |
1215 | struct fs_platform_info *fpi; | |
1216 | const u32 *data; | |
1217 | const u8 *mac_addr; | |
1218 | int privsize, len, ret = -ENODEV; | |
1219 | ||
1220 | fpi = kzalloc(sizeof(*fpi), GFP_KERNEL); | |
1221 | if (!fpi) | |
1222 | return -ENOMEM; | |
1223 | ||
1224 | if (!IS_FEC(match)) { | |
1225 | data = of_get_property(ofdev->node, "fsl,cpm-command", &len); | |
1226 | if (!data || len != 4) | |
1227 | goto out_free_fpi; | |
1228 | ||
1229 | fpi->cp_command = *data; | |
1230 | } | |
1231 | ||
1232 | fpi->rx_ring = 32; | |
1233 | fpi->tx_ring = 32; | |
1234 | fpi->rx_copybreak = 240; | |
1235 | fpi->use_napi = 0; | |
1236 | fpi->napi_weight = 17; | |
1237 | ||
1238 | ret = find_phy(ofdev->node, fpi); | |
1239 | if (ret) | |
1240 | goto out_free_fpi; | |
1241 | ||
1242 | privsize = sizeof(*fep) + | |
1243 | sizeof(struct sk_buff **) * | |
1244 | (fpi->rx_ring + fpi->tx_ring); | |
1245 | ||
1246 | ndev = alloc_etherdev(privsize); | |
1247 | if (!ndev) { | |
1248 | ret = -ENOMEM; | |
1249 | goto out_free_fpi; | |
1250 | } | |
1251 | ||
1252 | SET_MODULE_OWNER(ndev); | |
1253 | dev_set_drvdata(&ofdev->dev, ndev); | |
1254 | ||
1255 | fep = netdev_priv(ndev); | |
1256 | fep->dev = &ofdev->dev; | |
1257 | fep->fpi = fpi; | |
1258 | fep->ops = match->data; | |
1259 | ||
1260 | ret = fep->ops->setup_data(ndev); | |
1261 | if (ret) | |
1262 | goto out_free_dev; | |
1263 | ||
1264 | fep->rx_skbuff = (struct sk_buff **)&fep[1]; | |
1265 | fep->tx_skbuff = fep->rx_skbuff + fpi->rx_ring; | |
1266 | ||
1267 | spin_lock_init(&fep->lock); | |
1268 | spin_lock_init(&fep->tx_lock); | |
1269 | ||
1270 | mac_addr = of_get_mac_address(ofdev->node); | |
1271 | if (mac_addr) | |
1272 | memcpy(ndev->dev_addr, mac_addr, 6); | |
1273 | ||
1274 | ret = fep->ops->allocate_bd(ndev); | |
1275 | if (ret) | |
1276 | goto out_cleanup_data; | |
1277 | ||
1278 | fep->rx_bd_base = fep->ring_base; | |
1279 | fep->tx_bd_base = fep->rx_bd_base + fpi->rx_ring; | |
1280 | ||
1281 | fep->tx_ring = fpi->tx_ring; | |
1282 | fep->rx_ring = fpi->rx_ring; | |
1283 | ||
1284 | ndev->open = fs_enet_open; | |
1285 | ndev->hard_start_xmit = fs_enet_start_xmit; | |
1286 | ndev->tx_timeout = fs_timeout; | |
1287 | ndev->watchdog_timeo = 2 * HZ; | |
1288 | ndev->stop = fs_enet_close; | |
1289 | ndev->get_stats = fs_enet_get_stats; | |
1290 | ndev->set_multicast_list = fs_set_multicast_list; | |
1291 | if (fpi->use_napi) { | |
1292 | ndev->poll = fs_enet_rx_napi; | |
1293 | ndev->weight = fpi->napi_weight; | |
1294 | } | |
1295 | ndev->ethtool_ops = &fs_ethtool_ops; | |
1296 | ndev->do_ioctl = fs_ioctl; | |
1297 | ||
1298 | init_timer(&fep->phy_timer_list); | |
1299 | ||
1300 | netif_carrier_off(ndev); | |
1301 | ||
1302 | ret = register_netdev(ndev); | |
1303 | if (ret) | |
1304 | goto out_free_bd; | |
1305 | ||
1306 | printk(KERN_INFO "%s: fs_enet: %02x:%02x:%02x:%02x:%02x:%02x\n", | |
1307 | ndev->name, | |
1308 | ndev->dev_addr[0], ndev->dev_addr[1], ndev->dev_addr[2], | |
1309 | ndev->dev_addr[3], ndev->dev_addr[4], ndev->dev_addr[5]); | |
1310 | ||
1311 | return 0; | |
1312 | ||
1313 | out_free_bd: | |
1314 | fep->ops->free_bd(ndev); | |
1315 | out_cleanup_data: | |
1316 | fep->ops->cleanup_data(ndev); | |
1317 | out_free_dev: | |
1318 | free_netdev(ndev); | |
1319 | dev_set_drvdata(&ofdev->dev, NULL); | |
1320 | out_free_fpi: | |
1321 | kfree(fpi); | |
1322 | return ret; | |
1323 | } | |
1324 | ||
1325 | static int fs_enet_remove(struct of_device *ofdev) | |
1326 | { | |
1327 | struct net_device *ndev = dev_get_drvdata(&ofdev->dev); | |
1328 | struct fs_enet_private *fep = netdev_priv(ndev); | |
1329 | ||
1330 | unregister_netdev(ndev); | |
1331 | ||
1332 | fep->ops->free_bd(ndev); | |
1333 | fep->ops->cleanup_data(ndev); | |
1334 | dev_set_drvdata(fep->dev, NULL); | |
1335 | ||
1336 | free_netdev(ndev); | |
1337 | return 0; | |
1338 | } | |
1339 | ||
1340 | static struct of_device_id fs_enet_match[] = { | |
1341 | #ifdef CONFIG_FS_ENET_HAS_SCC | |
1342 | { | |
1343 | .compatible = "fsl,cpm1-scc-enet", | |
1344 | .data = (void *)&fs_scc_ops, | |
1345 | }, | |
1346 | #endif | |
1347 | #ifdef CONFIG_FS_ENET_HAS_FCC | |
1348 | { | |
1349 | .compatible = "fsl,cpm2-fcc-enet", | |
1350 | .data = (void *)&fs_fcc_ops, | |
1351 | }, | |
1352 | #endif | |
1353 | #ifdef CONFIG_FS_ENET_HAS_FEC | |
1354 | { | |
1355 | .compatible = "fsl,pq1-fec-enet", | |
1356 | .data = (void *)&fs_fec_ops, | |
1357 | }, | |
1358 | #endif | |
1359 | {} | |
1360 | }; | |
1361 | ||
1362 | static struct of_platform_driver fs_enet_driver = { | |
1363 | .name = "fs_enet", | |
1364 | .match_table = fs_enet_match, | |
1365 | .probe = fs_enet_probe, | |
1366 | .remove = fs_enet_remove, | |
1367 | }; | |
1368 | ||
1369 | static int __init fs_init(void) | |
1370 | { | |
1371 | int r = setup_immap(); | |
1372 | if (r != 0) | |
1373 | return r; | |
1374 | ||
1375 | r = of_register_platform_driver(&fs_enet_driver); | |
1376 | if (r != 0) | |
1377 | goto out; | |
1378 | ||
1379 | return 0; | |
1380 | ||
1381 | out: | |
1382 | cleanup_immap(); | |
1383 | return r; | |
1384 | } | |
1385 | ||
1386 | static void __exit fs_cleanup(void) | |
1387 | { | |
1388 | of_unregister_platform_driver(&fs_enet_driver); | |
1389 | cleanup_immap(); | |
1390 | } | |
1391 | #else | |
48257c4f PA |
1392 | static int __devinit fs_enet_probe(struct device *dev) |
1393 | { | |
1394 | struct net_device *ndev; | |
1395 | ||
1396 | /* no fixup - no device */ | |
1397 | if (dev->platform_data == NULL) { | |
1398 | printk(KERN_INFO "fs_enet: " | |
1399 | "probe called with no platform data; " | |
1400 | "remove unused devices\n"); | |
1401 | return -ENODEV; | |
1402 | } | |
1403 | ||
1404 | ndev = fs_init_instance(dev, dev->platform_data); | |
1405 | if (IS_ERR(ndev)) | |
1406 | return PTR_ERR(ndev); | |
1407 | return 0; | |
1408 | } | |
1409 | ||
1410 | static int fs_enet_remove(struct device *dev) | |
1411 | { | |
1412 | return fs_cleanup_instance(dev_get_drvdata(dev)); | |
1413 | } | |
1414 | ||
1415 | static struct device_driver fs_enet_fec_driver = { | |
1416 | .name = "fsl-cpm-fec", | |
1417 | .bus = &platform_bus_type, | |
1418 | .probe = fs_enet_probe, | |
1419 | .remove = fs_enet_remove, | |
1420 | #ifdef CONFIG_PM | |
1421 | /* .suspend = fs_enet_suspend, TODO */ | |
1422 | /* .resume = fs_enet_resume, TODO */ | |
1423 | #endif | |
1424 | }; | |
1425 | ||
1426 | static struct device_driver fs_enet_scc_driver = { | |
1427 | .name = "fsl-cpm-scc", | |
1428 | .bus = &platform_bus_type, | |
1429 | .probe = fs_enet_probe, | |
1430 | .remove = fs_enet_remove, | |
1431 | #ifdef CONFIG_PM | |
1432 | /* .suspend = fs_enet_suspend, TODO */ | |
1433 | /* .resume = fs_enet_resume, TODO */ | |
1434 | #endif | |
1435 | }; | |
1436 | ||
1437 | static struct device_driver fs_enet_fcc_driver = { | |
1438 | .name = "fsl-cpm-fcc", | |
1439 | .bus = &platform_bus_type, | |
1440 | .probe = fs_enet_probe, | |
1441 | .remove = fs_enet_remove, | |
1442 | #ifdef CONFIG_PM | |
1443 | /* .suspend = fs_enet_suspend, TODO */ | |
1444 | /* .resume = fs_enet_resume, TODO */ | |
1445 | #endif | |
1446 | }; | |
1447 | ||
1448 | static int __init fs_init(void) | |
1449 | { | |
1450 | int r; | |
1451 | ||
1452 | printk(KERN_INFO | |
1453 | "%s", version); | |
1454 | ||
1455 | r = setup_immap(); | |
1456 | if (r != 0) | |
1457 | return r; | |
5b4b8454 VB |
1458 | |
1459 | #ifdef CONFIG_FS_ENET_HAS_FCC | |
1460 | /* let's insert mii stuff */ | |
1461 | r = fs_enet_mdio_bb_init(); | |
1462 | ||
1463 | if (r != 0) { | |
1464 | printk(KERN_ERR DRV_MODULE_NAME | |
1465 | "BB PHY init failed.\n"); | |
1466 | return r; | |
1467 | } | |
1468 | r = driver_register(&fs_enet_fcc_driver); | |
48257c4f PA |
1469 | if (r != 0) |
1470 | goto err; | |
5b4b8454 | 1471 | #endif |
48257c4f | 1472 | |
5b4b8454 VB |
1473 | #ifdef CONFIG_FS_ENET_HAS_FEC |
1474 | r = fs_enet_mdio_fec_init(); | |
1475 | if (r != 0) { | |
1476 | printk(KERN_ERR DRV_MODULE_NAME | |
1477 | "FEC PHY init failed.\n"); | |
1478 | return r; | |
1479 | } | |
1480 | ||
1481 | r = driver_register(&fs_enet_fec_driver); | |
48257c4f PA |
1482 | if (r != 0) |
1483 | goto err; | |
5b4b8454 | 1484 | #endif |
48257c4f | 1485 | |
5b4b8454 | 1486 | #ifdef CONFIG_FS_ENET_HAS_SCC |
48257c4f PA |
1487 | r = driver_register(&fs_enet_scc_driver); |
1488 | if (r != 0) | |
1489 | goto err; | |
5b4b8454 | 1490 | #endif |
48257c4f PA |
1491 | |
1492 | return 0; | |
1493 | err: | |
1494 | cleanup_immap(); | |
1495 | return r; | |
48257c4f PA |
1496 | } |
1497 | ||
1498 | static void __exit fs_cleanup(void) | |
1499 | { | |
1500 | driver_unregister(&fs_enet_fec_driver); | |
1501 | driver_unregister(&fs_enet_fcc_driver); | |
1502 | driver_unregister(&fs_enet_scc_driver); | |
1503 | cleanup_immap(); | |
1504 | } | |
976de6a8 | 1505 | #endif |
48257c4f | 1506 | |
9b8ee8e7 VB |
1507 | #ifdef CONFIG_NET_POLL_CONTROLLER |
1508 | static void fs_enet_netpoll(struct net_device *dev) | |
1509 | { | |
1510 | disable_irq(dev->irq); | |
1511 | fs_enet_interrupt(dev->irq, dev, NULL); | |
1512 | enable_irq(dev->irq); | |
1513 | } | |
1514 | #endif | |
1515 | ||
48257c4f PA |
1516 | /**************************************************************************************/ |
1517 | ||
1518 | module_init(fs_init); | |
1519 | module_exit(fs_cleanup); |