diff options
author | Pantelis Antoniou <pantelis.antoniou@gmail.com> | 2005-10-28 16:25:58 -0400 |
---|---|---|
committer | Jeff Garzik <jgarzik@pobox.com> | 2005-10-28 16:25:58 -0400 |
commit | 48257c4f168e5d040394aeca4d37b59f68e0d36b (patch) | |
tree | 7e553a6018862338d80fb5b0e4070a371a8fb001 /drivers/net/fs_enet | |
parent | d8840ac907c7943bc7e196b11812adfa95cb28ef (diff) |
Add fs_enet ethernet network driver, for several embedded platforms.
Diffstat (limited to 'drivers/net/fs_enet')
-rw-r--r-- | drivers/net/fs_enet/Kconfig | 20 | ||||
-rw-r--r-- | drivers/net/fs_enet/Makefile | 10 | ||||
-rw-r--r-- | drivers/net/fs_enet/fs_enet-main.c | 1226 | ||||
-rw-r--r-- | drivers/net/fs_enet/fs_enet-mii.c | 507 | ||||
-rw-r--r-- | drivers/net/fs_enet/fs_enet.h | 245 | ||||
-rw-r--r-- | drivers/net/fs_enet/mac-fcc.c | 578 | ||||
-rw-r--r-- | drivers/net/fs_enet/mac-fec.c | 653 | ||||
-rw-r--r-- | drivers/net/fs_enet/mac-scc.c | 524 | ||||
-rw-r--r-- | drivers/net/fs_enet/mii-bitbang.c | 405 | ||||
-rw-r--r-- | drivers/net/fs_enet/mii-fixed.c | 92 |
10 files changed, 4260 insertions, 0 deletions
diff --git a/drivers/net/fs_enet/Kconfig b/drivers/net/fs_enet/Kconfig new file mode 100644 index 000000000000..6aaee67dd4b7 --- /dev/null +++ b/drivers/net/fs_enet/Kconfig | |||
@@ -0,0 +1,20 @@ | |||
1 | config FS_ENET | ||
2 | tristate "Freescale Ethernet Driver" | ||
3 | depends on NET_ETHERNET && (CPM1 || CPM2) | ||
4 | select MII | ||
5 | |||
6 | config FS_ENET_HAS_SCC | ||
7 | bool "Chip has an SCC usable for ethernet" | ||
8 | depends on FS_ENET && (CPM1 || CPM2) | ||
9 | default y | ||
10 | |||
11 | config FS_ENET_HAS_FCC | ||
12 | bool "Chip has an FCC usable for ethernet" | ||
13 | depends on FS_ENET && CPM2 | ||
14 | default y | ||
15 | |||
16 | config FS_ENET_HAS_FEC | ||
17 | bool "Chip has an FEC usable for ethernet" | ||
18 | depends on FS_ENET && CPM1 | ||
19 | default y | ||
20 | |||
diff --git a/drivers/net/fs_enet/Makefile b/drivers/net/fs_enet/Makefile new file mode 100644 index 000000000000..d6dd3f2fb43e --- /dev/null +++ b/drivers/net/fs_enet/Makefile | |||
@@ -0,0 +1,10 @@ | |||
1 | # | ||
2 | # Makefile for the Freescale Ethernet controllers | ||
3 | # | ||
4 | |||
5 | obj-$(CONFIG_FS_ENET) += fs_enet.o | ||
6 | |||
7 | obj-$(CONFIG_8xx) += mac-fec.o mac-scc.o | ||
8 | obj-$(CONFIG_8260) += mac-fcc.o | ||
9 | |||
10 | fs_enet-objs := fs_enet-main.o fs_enet-mii.o mii-bitbang.o mii-fixed.o | ||
diff --git a/drivers/net/fs_enet/fs_enet-main.c b/drivers/net/fs_enet/fs_enet-main.c new file mode 100644 index 000000000000..44fac7373289 --- /dev/null +++ b/drivers/net/fs_enet/fs_enet-main.c | |||
@@ -0,0 +1,1226 @@ | |||
1 | /* | ||
2 | * Combined Ethernet driver for Motorola MPC8xx and MPC82xx. | ||
3 | * | ||
4 | * Copyright (c) 2003 Intracom S.A. | ||
5 | * by Pantelis Antoniou <panto@intracom.gr> | ||
6 | * | ||
7 | * 2005 (c) MontaVista Software, Inc. | ||
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 | * | ||
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 | ||
15 | * kind, whether express or implied. | ||
16 | */ | ||
17 | |||
18 | #include <linux/config.h> | ||
19 | #include <linux/module.h> | ||
20 | #include <linux/kernel.h> | ||
21 | #include <linux/types.h> | ||
22 | #include <linux/sched.h> | ||
23 | #include <linux/string.h> | ||
24 | #include <linux/ptrace.h> | ||
25 | #include <linux/errno.h> | ||
26 | #include <linux/ioport.h> | ||
27 | #include <linux/slab.h> | ||
28 | #include <linux/interrupt.h> | ||
29 | #include <linux/pci.h> | ||
30 | #include <linux/init.h> | ||
31 | #include <linux/delay.h> | ||
32 | #include <linux/netdevice.h> | ||
33 | #include <linux/etherdevice.h> | ||
34 | #include <linux/skbuff.h> | ||
35 | #include <linux/spinlock.h> | ||
36 | #include <linux/mii.h> | ||
37 | #include <linux/ethtool.h> | ||
38 | #include <linux/bitops.h> | ||
39 | #include <linux/fs.h> | ||
40 | |||
41 | #include <linux/vmalloc.h> | ||
42 | #include <asm/pgtable.h> | ||
43 | |||
44 | #include <asm/pgtable.h> | ||
45 | #include <asm/irq.h> | ||
46 | #include <asm/uaccess.h> | ||
47 | |||
48 | #include "fs_enet.h" | ||
49 | |||
50 | /*************************************************/ | ||
51 | |||
52 | static char version[] __devinitdata = | ||
53 | DRV_MODULE_NAME ".c:v" DRV_MODULE_VERSION " (" DRV_MODULE_RELDATE ")" "\n"; | ||
54 | |||
55 | MODULE_AUTHOR("Pantelis Antoniou <panto@intracom.gr>"); | ||
56 | MODULE_DESCRIPTION("Freescale Ethernet Driver"); | ||
57 | MODULE_LICENSE("GPL"); | ||
58 | MODULE_VERSION(DRV_MODULE_VERSION); | ||
59 | |||
60 | MODULE_PARM(fs_enet_debug, "i"); | ||
61 | MODULE_PARM_DESC(fs_enet_debug, | ||
62 | "Freescale bitmapped debugging message enable value"); | ||
63 | |||
64 | int fs_enet_debug = -1; /* -1 == use FS_ENET_DEF_MSG_ENABLE as value */ | ||
65 | |||
66 | static void fs_set_multicast_list(struct net_device *dev) | ||
67 | { | ||
68 | struct fs_enet_private *fep = netdev_priv(dev); | ||
69 | |||
70 | (*fep->ops->set_multicast_list)(dev); | ||
71 | } | ||
72 | |||
73 | /* NAPI receive function */ | ||
74 | static int fs_enet_rx_napi(struct net_device *dev, int *budget) | ||
75 | { | ||
76 | struct fs_enet_private *fep = netdev_priv(dev); | ||
77 | const struct fs_platform_info *fpi = fep->fpi; | ||
78 | cbd_t *bdp; | ||
79 | struct sk_buff *skb, *skbn, *skbt; | ||
80 | int received = 0; | ||
81 | u16 pkt_len, sc; | ||
82 | int curidx; | ||
83 | int rx_work_limit = 0; /* pacify gcc */ | ||
84 | |||
85 | rx_work_limit = min(dev->quota, *budget); | ||
86 | |||
87 | if (!netif_running(dev)) | ||
88 | return 0; | ||
89 | |||
90 | /* | ||
91 | * First, grab all of the stats for the incoming packet. | ||
92 | * These get messed up if we get called due to a busy condition. | ||
93 | */ | ||
94 | bdp = fep->cur_rx; | ||
95 | |||
96 | /* clear RX status bits for napi*/ | ||
97 | (*fep->ops->napi_clear_rx_event)(dev); | ||
98 | |||
99 | while (((sc = CBDR_SC(bdp)) & BD_ENET_RX_EMPTY) == 0) { | ||
100 | |||
101 | curidx = bdp - fep->rx_bd_base; | ||
102 | |||
103 | /* | ||
104 | * Since we have allocated space to hold a complete frame, | ||
105 | * the last indicator should be set. | ||
106 | */ | ||
107 | if ((sc & BD_ENET_RX_LAST) == 0) | ||
108 | printk(KERN_WARNING DRV_MODULE_NAME | ||
109 | ": %s rcv is not +last\n", | ||
110 | dev->name); | ||
111 | |||
112 | /* | ||
113 | * Check for errors. | ||
114 | */ | ||
115 | if (sc & (BD_ENET_RX_LG | BD_ENET_RX_SH | BD_ENET_RX_CL | | ||
116 | BD_ENET_RX_NO | BD_ENET_RX_CR | BD_ENET_RX_OV)) { | ||
117 | fep->stats.rx_errors++; | ||
118 | /* Frame too long or too short. */ | ||
119 | if (sc & (BD_ENET_RX_LG | BD_ENET_RX_SH)) | ||
120 | fep->stats.rx_length_errors++; | ||
121 | /* Frame alignment */ | ||
122 | if (sc & (BD_ENET_RX_NO | BD_ENET_RX_CL)) | ||
123 | fep->stats.rx_frame_errors++; | ||
124 | /* CRC Error */ | ||
125 | if (sc & BD_ENET_RX_CR) | ||
126 | fep->stats.rx_crc_errors++; | ||
127 | /* FIFO overrun */ | ||
128 | if (sc & BD_ENET_RX_OV) | ||
129 | fep->stats.rx_crc_errors++; | ||
130 | |||
131 | skb = fep->rx_skbuff[curidx]; | ||
132 | |||
133 | dma_unmap_single(fep->dev, skb->data, | ||
134 | L1_CACHE_ALIGN(PKT_MAXBUF_SIZE), | ||
135 | DMA_FROM_DEVICE); | ||
136 | |||
137 | skbn = skb; | ||
138 | |||
139 | } else { | ||
140 | |||
141 | /* napi, got packet but no quota */ | ||
142 | if (--rx_work_limit < 0) | ||
143 | break; | ||
144 | |||
145 | skb = fep->rx_skbuff[curidx]; | ||
146 | |||
147 | dma_unmap_single(fep->dev, skb->data, | ||
148 | L1_CACHE_ALIGN(PKT_MAXBUF_SIZE), | ||
149 | DMA_FROM_DEVICE); | ||
150 | |||
151 | /* | ||
152 | * Process the incoming frame. | ||
153 | */ | ||
154 | fep->stats.rx_packets++; | ||
155 | pkt_len = CBDR_DATLEN(bdp) - 4; /* remove CRC */ | ||
156 | fep->stats.rx_bytes += pkt_len + 4; | ||
157 | |||
158 | if (pkt_len <= fpi->rx_copybreak) { | ||
159 | /* +2 to make IP header L1 cache aligned */ | ||
160 | skbn = dev_alloc_skb(pkt_len + 2); | ||
161 | if (skbn != NULL) { | ||
162 | skb_reserve(skbn, 2); /* align IP header */ | ||
163 | memcpy(skbn->data, skb->data, pkt_len); | ||
164 | /* swap */ | ||
165 | skbt = skb; | ||
166 | skb = skbn; | ||
167 | skbn = skbt; | ||
168 | } | ||
169 | } else | ||
170 | skbn = dev_alloc_skb(ENET_RX_FRSIZE); | ||
171 | |||
172 | if (skbn != NULL) { | ||
173 | skb->dev = dev; | ||
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 { | ||
179 | printk(KERN_WARNING DRV_MODULE_NAME | ||
180 | ": %s Memory squeeze, dropping packet.\n", | ||
181 | dev->name); | ||
182 | fep->stats.rx_dropped++; | ||
183 | skbn = skb; | ||
184 | } | ||
185 | } | ||
186 | |||
187 | fep->rx_skbuff[curidx] = skbn; | ||
188 | CBDW_BUFADDR(bdp, dma_map_single(fep->dev, skbn->data, | ||
189 | L1_CACHE_ALIGN(PKT_MAXBUF_SIZE), | ||
190 | DMA_FROM_DEVICE)); | ||
191 | CBDW_DATLEN(bdp, 0); | ||
192 | CBDW_SC(bdp, (sc & ~BD_ENET_RX_STATS) | BD_ENET_RX_EMPTY); | ||
193 | |||
194 | /* | ||
195 | * Update BD pointer to next entry. | ||
196 | */ | ||
197 | if ((sc & BD_ENET_RX_WRAP) == 0) | ||
198 | bdp++; | ||
199 | else | ||
200 | bdp = fep->rx_bd_base; | ||
201 | |||
202 | (*fep->ops->rx_bd_done)(dev); | ||
203 | } | ||
204 | |||
205 | fep->cur_rx = bdp; | ||
206 | |||
207 | dev->quota -= received; | ||
208 | *budget -= received; | ||
209 | |||
210 | if (rx_work_limit < 0) | ||
211 | return 1; /* not done */ | ||
212 | |||
213 | /* done */ | ||
214 | netif_rx_complete(dev); | ||
215 | |||
216 | (*fep->ops->napi_enable_rx)(dev); | ||
217 | |||
218 | return 0; | ||
219 | } | ||
220 | |||
221 | /* non NAPI receive function */ | ||
222 | static int fs_enet_rx_non_napi(struct net_device *dev) | ||
223 | { | ||
224 | struct fs_enet_private *fep = netdev_priv(dev); | ||
225 | const struct fs_platform_info *fpi = fep->fpi; | ||
226 | cbd_t *bdp; | ||
227 | struct sk_buff *skb, *skbn, *skbt; | ||
228 | int received = 0; | ||
229 | u16 pkt_len, sc; | ||
230 | int curidx; | ||
231 | /* | ||
232 | * First, grab all of the stats for the incoming packet. | ||
233 | * These get messed up if we get called due to a busy condition. | ||
234 | */ | ||
235 | bdp = fep->cur_rx; | ||
236 | |||
237 | while (((sc = CBDR_SC(bdp)) & BD_ENET_RX_EMPTY) == 0) { | ||
238 | |||
239 | curidx = bdp - fep->rx_bd_base; | ||
240 | |||
241 | /* | ||
242 | * Since we have allocated space to hold a complete frame, | ||
243 | * the last indicator should be set. | ||
244 | */ | ||
245 | if ((sc & BD_ENET_RX_LAST) == 0) | ||
246 | printk(KERN_WARNING DRV_MODULE_NAME | ||
247 | ": %s rcv is not +last\n", | ||
248 | dev->name); | ||
249 | |||
250 | /* | ||
251 | * Check for errors. | ||
252 | */ | ||
253 | if (sc & (BD_ENET_RX_LG | BD_ENET_RX_SH | BD_ENET_RX_CL | | ||
254 | BD_ENET_RX_NO | BD_ENET_RX_CR | BD_ENET_RX_OV)) { | ||
255 | fep->stats.rx_errors++; | ||
256 | /* Frame too long or too short. */ | ||
257 | if (sc & (BD_ENET_RX_LG | BD_ENET_RX_SH)) | ||
258 | fep->stats.rx_length_errors++; | ||
259 | /* Frame alignment */ | ||
260 | if (sc & (BD_ENET_RX_NO | BD_ENET_RX_CL)) | ||
261 | fep->stats.rx_frame_errors++; | ||
262 | /* CRC Error */ | ||
263 | if (sc & BD_ENET_RX_CR) | ||
264 | fep->stats.rx_crc_errors++; | ||
265 | /* FIFO overrun */ | ||
266 | if (sc & BD_ENET_RX_OV) | ||
267 | fep->stats.rx_crc_errors++; | ||
268 | |||
269 | skb = fep->rx_skbuff[curidx]; | ||
270 | |||
271 | dma_unmap_single(fep->dev, skb->data, | ||
272 | L1_CACHE_ALIGN(PKT_MAXBUF_SIZE), | ||
273 | DMA_FROM_DEVICE); | ||
274 | |||
275 | skbn = skb; | ||
276 | |||
277 | } else { | ||
278 | |||
279 | skb = fep->rx_skbuff[curidx]; | ||
280 | |||
281 | dma_unmap_single(fep->dev, skb->data, | ||
282 | L1_CACHE_ALIGN(PKT_MAXBUF_SIZE), | ||
283 | DMA_FROM_DEVICE); | ||
284 | |||
285 | /* | ||
286 | * Process the incoming frame. | ||
287 | */ | ||
288 | fep->stats.rx_packets++; | ||
289 | pkt_len = CBDR_DATLEN(bdp) - 4; /* remove CRC */ | ||
290 | fep->stats.rx_bytes += pkt_len + 4; | ||
291 | |||
292 | if (pkt_len <= fpi->rx_copybreak) { | ||
293 | /* +2 to make IP header L1 cache aligned */ | ||
294 | skbn = dev_alloc_skb(pkt_len + 2); | ||
295 | if (skbn != NULL) { | ||
296 | skb_reserve(skbn, 2); /* align IP header */ | ||
297 | memcpy(skbn->data, skb->data, pkt_len); | ||
298 | /* swap */ | ||
299 | skbt = skb; | ||
300 | skb = skbn; | ||
301 | skbn = skbt; | ||
302 | } | ||
303 | } else | ||
304 | skbn = dev_alloc_skb(ENET_RX_FRSIZE); | ||
305 | |||
306 | if (skbn != NULL) { | ||
307 | skb->dev = dev; | ||
308 | skb_put(skb, pkt_len); /* Make room */ | ||
309 | skb->protocol = eth_type_trans(skb, dev); | ||
310 | received++; | ||
311 | netif_rx(skb); | ||
312 | } else { | ||
313 | printk(KERN_WARNING DRV_MODULE_NAME | ||
314 | ": %s Memory squeeze, dropping packet.\n", | ||
315 | dev->name); | ||
316 | fep->stats.rx_dropped++; | ||
317 | skbn = skb; | ||
318 | } | ||
319 | } | ||
320 | |||
321 | fep->rx_skbuff[curidx] = skbn; | ||
322 | CBDW_BUFADDR(bdp, dma_map_single(fep->dev, skbn->data, | ||
323 | L1_CACHE_ALIGN(PKT_MAXBUF_SIZE), | ||
324 | DMA_FROM_DEVICE)); | ||
325 | CBDW_DATLEN(bdp, 0); | ||
326 | CBDW_SC(bdp, (sc & ~BD_ENET_RX_STATS) | BD_ENET_RX_EMPTY); | ||
327 | |||
328 | /* | ||
329 | * Update BD pointer to next entry. | ||
330 | */ | ||
331 | if ((sc & BD_ENET_RX_WRAP) == 0) | ||
332 | bdp++; | ||
333 | else | ||
334 | bdp = fep->rx_bd_base; | ||
335 | |||
336 | (*fep->ops->rx_bd_done)(dev); | ||
337 | } | ||
338 | |||
339 | fep->cur_rx = bdp; | ||
340 | |||
341 | return 0; | ||
342 | } | ||
343 | |||
344 | static void fs_enet_tx(struct net_device *dev) | ||
345 | { | ||
346 | struct fs_enet_private *fep = netdev_priv(dev); | ||
347 | cbd_t *bdp; | ||
348 | struct sk_buff *skb; | ||
349 | int dirtyidx, do_wake, do_restart; | ||
350 | u16 sc; | ||
351 | |||
352 | spin_lock(&fep->lock); | ||
353 | bdp = fep->dirty_tx; | ||
354 | |||
355 | do_wake = do_restart = 0; | ||
356 | while (((sc = CBDR_SC(bdp)) & BD_ENET_TX_READY) == 0) { | ||
357 | |||
358 | dirtyidx = bdp - fep->tx_bd_base; | ||
359 | |||
360 | if (fep->tx_free == fep->tx_ring) | ||
361 | break; | ||
362 | |||
363 | skb = fep->tx_skbuff[dirtyidx]; | ||
364 | |||
365 | /* | ||
366 | * Check for errors. | ||
367 | */ | ||
368 | if (sc & (BD_ENET_TX_HB | BD_ENET_TX_LC | | ||
369 | BD_ENET_TX_RL | BD_ENET_TX_UN | BD_ENET_TX_CSL)) { | ||
370 | |||
371 | if (sc & BD_ENET_TX_HB) /* No heartbeat */ | ||
372 | fep->stats.tx_heartbeat_errors++; | ||
373 | if (sc & BD_ENET_TX_LC) /* Late collision */ | ||
374 | fep->stats.tx_window_errors++; | ||
375 | if (sc & BD_ENET_TX_RL) /* Retrans limit */ | ||
376 | fep->stats.tx_aborted_errors++; | ||
377 | if (sc & BD_ENET_TX_UN) /* Underrun */ | ||
378 | fep->stats.tx_fifo_errors++; | ||
379 | if (sc & BD_ENET_TX_CSL) /* Carrier lost */ | ||
380 | fep->stats.tx_carrier_errors++; | ||
381 | |||
382 | if (sc & (BD_ENET_TX_LC | BD_ENET_TX_RL | BD_ENET_TX_UN)) { | ||
383 | fep->stats.tx_errors++; | ||
384 | do_restart = 1; | ||
385 | } | ||
386 | } else | ||
387 | fep->stats.tx_packets++; | ||
388 | |||
389 | if (sc & BD_ENET_TX_READY) | ||
390 | printk(KERN_WARNING DRV_MODULE_NAME | ||
391 | ": %s HEY! Enet xmit interrupt and TX_READY.\n", | ||
392 | dev->name); | ||
393 | |||
394 | /* | ||
395 | * Deferred means some collisions occurred during transmit, | ||
396 | * but we eventually sent the packet OK. | ||
397 | */ | ||
398 | if (sc & BD_ENET_TX_DEF) | ||
399 | fep->stats.collisions++; | ||
400 | |||
401 | /* unmap */ | ||
402 | dma_unmap_single(fep->dev, skb->data, skb->len, DMA_TO_DEVICE); | ||
403 | |||
404 | /* | ||
405 | * Free the sk buffer associated with this last transmit. | ||
406 | */ | ||
407 | dev_kfree_skb_irq(skb); | ||
408 | fep->tx_skbuff[dirtyidx] = NULL; | ||
409 | |||
410 | /* | ||
411 | * Update pointer to next buffer descriptor to be transmitted. | ||
412 | */ | ||
413 | if ((sc & BD_ENET_TX_WRAP) == 0) | ||
414 | bdp++; | ||
415 | else | ||
416 | bdp = fep->tx_bd_base; | ||
417 | |||
418 | /* | ||
419 | * Since we have freed up a buffer, the ring is no longer | ||
420 | * full. | ||
421 | */ | ||
422 | if (!fep->tx_free++) | ||
423 | do_wake = 1; | ||
424 | } | ||
425 | |||
426 | fep->dirty_tx = bdp; | ||
427 | |||
428 | if (do_restart) | ||
429 | (*fep->ops->tx_restart)(dev); | ||
430 | |||
431 | spin_unlock(&fep->lock); | ||
432 | |||
433 | if (do_wake) | ||
434 | netif_wake_queue(dev); | ||
435 | } | ||
436 | |||
437 | /* | ||
438 | * The interrupt handler. | ||
439 | * This is called from the MPC core interrupt. | ||
440 | */ | ||
441 | static irqreturn_t | ||
442 | fs_enet_interrupt(int irq, void *dev_id, struct pt_regs *regs) | ||
443 | { | ||
444 | struct net_device *dev = dev_id; | ||
445 | struct fs_enet_private *fep; | ||
446 | const struct fs_platform_info *fpi; | ||
447 | u32 int_events; | ||
448 | u32 int_clr_events; | ||
449 | int nr, napi_ok; | ||
450 | int handled; | ||
451 | |||
452 | fep = netdev_priv(dev); | ||
453 | fpi = fep->fpi; | ||
454 | |||
455 | nr = 0; | ||
456 | while ((int_events = (*fep->ops->get_int_events)(dev)) != 0) { | ||
457 | |||
458 | nr++; | ||
459 | |||
460 | int_clr_events = int_events; | ||
461 | if (fpi->use_napi) | ||
462 | int_clr_events &= ~fep->ev_napi_rx; | ||
463 | |||
464 | (*fep->ops->clear_int_events)(dev, int_clr_events); | ||
465 | |||
466 | if (int_events & fep->ev_err) | ||
467 | (*fep->ops->ev_error)(dev, int_events); | ||
468 | |||
469 | if (int_events & fep->ev_rx) { | ||
470 | if (!fpi->use_napi) | ||
471 | fs_enet_rx_non_napi(dev); | ||
472 | else { | ||
473 | napi_ok = netif_rx_schedule_prep(dev); | ||
474 | |||
475 | (*fep->ops->napi_disable_rx)(dev); | ||
476 | (*fep->ops->clear_int_events)(dev, fep->ev_napi_rx); | ||
477 | |||
478 | /* NOTE: it is possible for FCCs in NAPI mode */ | ||
479 | /* to submit a spurious interrupt while in poll */ | ||
480 | if (napi_ok) | ||
481 | __netif_rx_schedule(dev); | ||
482 | } | ||
483 | } | ||
484 | |||
485 | if (int_events & fep->ev_tx) | ||
486 | fs_enet_tx(dev); | ||
487 | } | ||
488 | |||
489 | handled = nr > 0; | ||
490 | return IRQ_RETVAL(handled); | ||
491 | } | ||
492 | |||
493 | void fs_init_bds(struct net_device *dev) | ||
494 | { | ||
495 | struct fs_enet_private *fep = netdev_priv(dev); | ||
496 | cbd_t *bdp; | ||
497 | struct sk_buff *skb; | ||
498 | int i; | ||
499 | |||
500 | fs_cleanup_bds(dev); | ||
501 | |||
502 | fep->dirty_tx = fep->cur_tx = fep->tx_bd_base; | ||
503 | fep->tx_free = fep->tx_ring; | ||
504 | fep->cur_rx = fep->rx_bd_base; | ||
505 | |||
506 | /* | ||
507 | * Initialize the receive buffer descriptors. | ||
508 | */ | ||
509 | for (i = 0, bdp = fep->rx_bd_base; i < fep->rx_ring; i++, bdp++) { | ||
510 | skb = dev_alloc_skb(ENET_RX_FRSIZE); | ||
511 | if (skb == NULL) { | ||
512 | printk(KERN_WARNING DRV_MODULE_NAME | ||
513 | ": %s Memory squeeze, unable to allocate skb\n", | ||
514 | dev->name); | ||
515 | break; | ||
516 | } | ||
517 | fep->rx_skbuff[i] = skb; | ||
518 | skb->dev = dev; | ||
519 | CBDW_BUFADDR(bdp, | ||
520 | dma_map_single(fep->dev, skb->data, | ||
521 | L1_CACHE_ALIGN(PKT_MAXBUF_SIZE), | ||
522 | DMA_FROM_DEVICE)); | ||
523 | CBDW_DATLEN(bdp, 0); /* zero */ | ||
524 | CBDW_SC(bdp, BD_ENET_RX_EMPTY | | ||
525 | ((i < fep->rx_ring - 1) ? 0 : BD_SC_WRAP)); | ||
526 | } | ||
527 | /* | ||
528 | * if we failed, fillup remainder | ||
529 | */ | ||
530 | for (; i < fep->rx_ring; i++, bdp++) { | ||
531 | fep->rx_skbuff[i] = NULL; | ||
532 | CBDW_SC(bdp, (i < fep->rx_ring - 1) ? 0 : BD_SC_WRAP); | ||
533 | } | ||
534 | |||
535 | /* | ||
536 | * ...and the same for transmit. | ||
537 | */ | ||
538 | for (i = 0, bdp = fep->tx_bd_base; i < fep->tx_ring; i++, bdp++) { | ||
539 | fep->tx_skbuff[i] = NULL; | ||
540 | CBDW_BUFADDR(bdp, 0); | ||
541 | CBDW_DATLEN(bdp, 0); | ||
542 | CBDW_SC(bdp, (i < fep->tx_ring - 1) ? 0 : BD_SC_WRAP); | ||
543 | } | ||
544 | } | ||
545 | |||
546 | void fs_cleanup_bds(struct net_device *dev) | ||
547 | { | ||
548 | struct fs_enet_private *fep = netdev_priv(dev); | ||
549 | struct sk_buff *skb; | ||
550 | int i; | ||
551 | |||
552 | /* | ||
553 | * Reset SKB transmit buffers. | ||
554 | */ | ||
555 | for (i = 0; i < fep->tx_ring; i++) { | ||
556 | if ((skb = fep->tx_skbuff[i]) == NULL) | ||
557 | continue; | ||
558 | |||
559 | /* unmap */ | ||
560 | dma_unmap_single(fep->dev, skb->data, skb->len, DMA_TO_DEVICE); | ||
561 | |||
562 | fep->tx_skbuff[i] = NULL; | ||
563 | dev_kfree_skb(skb); | ||
564 | } | ||
565 | |||
566 | /* | ||
567 | * Reset SKB receive buffers | ||
568 | */ | ||
569 | for (i = 0; i < fep->rx_ring; i++) { | ||
570 | if ((skb = fep->rx_skbuff[i]) == NULL) | ||
571 | continue; | ||
572 | |||
573 | /* unmap */ | ||
574 | dma_unmap_single(fep->dev, skb->data, | ||
575 | L1_CACHE_ALIGN(PKT_MAXBUF_SIZE), | ||
576 | DMA_FROM_DEVICE); | ||
577 | |||
578 | fep->rx_skbuff[i] = NULL; | ||
579 | |||
580 | dev_kfree_skb(skb); | ||
581 | } | ||
582 | } | ||
583 | |||
584 | /**********************************************************************************/ | ||
585 | |||
586 | static int fs_enet_start_xmit(struct sk_buff *skb, struct net_device *dev) | ||
587 | { | ||
588 | struct fs_enet_private *fep = netdev_priv(dev); | ||
589 | cbd_t *bdp; | ||
590 | int curidx; | ||
591 | u16 sc; | ||
592 | unsigned long flags; | ||
593 | |||
594 | spin_lock_irqsave(&fep->tx_lock, flags); | ||
595 | |||
596 | /* | ||
597 | * Fill in a Tx ring entry | ||
598 | */ | ||
599 | bdp = fep->cur_tx; | ||
600 | |||
601 | if (!fep->tx_free || (CBDR_SC(bdp) & BD_ENET_TX_READY)) { | ||
602 | netif_stop_queue(dev); | ||
603 | spin_unlock_irqrestore(&fep->tx_lock, flags); | ||
604 | |||
605 | /* | ||
606 | * Ooops. All transmit buffers are full. Bail out. | ||
607 | * This should not happen, since the tx queue should be stopped. | ||
608 | */ | ||
609 | printk(KERN_WARNING DRV_MODULE_NAME | ||
610 | ": %s tx queue full!.\n", dev->name); | ||
611 | return NETDEV_TX_BUSY; | ||
612 | } | ||
613 | |||
614 | curidx = bdp - fep->tx_bd_base; | ||
615 | /* | ||
616 | * Clear all of the status flags. | ||
617 | */ | ||
618 | CBDC_SC(bdp, BD_ENET_TX_STATS); | ||
619 | |||
620 | /* | ||
621 | * Save skb pointer. | ||
622 | */ | ||
623 | fep->tx_skbuff[curidx] = skb; | ||
624 | |||
625 | fep->stats.tx_bytes += skb->len; | ||
626 | |||
627 | /* | ||
628 | * Push the data cache so the CPM does not get stale memory data. | ||
629 | */ | ||
630 | CBDW_BUFADDR(bdp, dma_map_single(fep->dev, | ||
631 | skb->data, skb->len, DMA_TO_DEVICE)); | ||
632 | CBDW_DATLEN(bdp, skb->len); | ||
633 | |||
634 | dev->trans_start = jiffies; | ||
635 | |||
636 | /* | ||
637 | * If this was the last BD in the ring, start at the beginning again. | ||
638 | */ | ||
639 | if ((CBDR_SC(bdp) & BD_ENET_TX_WRAP) == 0) | ||
640 | fep->cur_tx++; | ||
641 | else | ||
642 | fep->cur_tx = fep->tx_bd_base; | ||
643 | |||
644 | if (!--fep->tx_free) | ||
645 | netif_stop_queue(dev); | ||
646 | |||
647 | /* Trigger transmission start */ | ||
648 | sc = BD_ENET_TX_READY | BD_ENET_TX_INTR | | ||
649 | BD_ENET_TX_LAST | BD_ENET_TX_TC; | ||
650 | |||
651 | /* note that while FEC does not have this bit | ||
652 | * it marks it as available for software use | ||
653 | * yay for hw reuse :) */ | ||
654 | if (skb->len <= 60) | ||
655 | sc |= BD_ENET_TX_PAD; | ||
656 | CBDS_SC(bdp, sc); | ||
657 | |||
658 | (*fep->ops->tx_kickstart)(dev); | ||
659 | |||
660 | spin_unlock_irqrestore(&fep->tx_lock, flags); | ||
661 | |||
662 | return NETDEV_TX_OK; | ||
663 | } | ||
664 | |||
665 | static int fs_request_irq(struct net_device *dev, int irq, const char *name, | ||
666 | irqreturn_t (*irqf)(int irq, void *dev_id, struct pt_regs *regs)) | ||
667 | { | ||
668 | struct fs_enet_private *fep = netdev_priv(dev); | ||
669 | |||
670 | (*fep->ops->pre_request_irq)(dev, irq); | ||
671 | return request_irq(irq, irqf, SA_SHIRQ, name, dev); | ||
672 | } | ||
673 | |||
674 | static void fs_free_irq(struct net_device *dev, int irq) | ||
675 | { | ||
676 | struct fs_enet_private *fep = netdev_priv(dev); | ||
677 | |||
678 | free_irq(irq, dev); | ||
679 | (*fep->ops->post_free_irq)(dev, irq); | ||
680 | } | ||
681 | |||
682 | /**********************************************************************************/ | ||
683 | |||
684 | /* This interrupt occurs when the PHY detects a link change. */ | ||
685 | static irqreturn_t | ||
686 | fs_mii_link_interrupt(int irq, void *dev_id, struct pt_regs *regs) | ||
687 | { | ||
688 | struct net_device *dev = dev_id; | ||
689 | struct fs_enet_private *fep; | ||
690 | const struct fs_platform_info *fpi; | ||
691 | |||
692 | fep = netdev_priv(dev); | ||
693 | fpi = fep->fpi; | ||
694 | |||
695 | /* | ||
696 | * Acknowledge the interrupt if possible. If we have not | ||
697 | * found the PHY yet we can't process or acknowledge the | ||
698 | * interrupt now. Instead we ignore this interrupt for now, | ||
699 | * which we can do since it is edge triggered. It will be | ||
700 | * acknowledged later by fs_enet_open(). | ||
701 | */ | ||
702 | if (!fep->phy) | ||
703 | return IRQ_NONE; | ||
704 | |||
705 | fs_mii_ack_int(dev); | ||
706 | fs_mii_link_status_change_check(dev, 0); | ||
707 | |||
708 | return IRQ_HANDLED; | ||
709 | } | ||
710 | |||
711 | static void fs_timeout(struct net_device *dev) | ||
712 | { | ||
713 | struct fs_enet_private *fep = netdev_priv(dev); | ||
714 | unsigned long flags; | ||
715 | int wake = 0; | ||
716 | |||
717 | fep->stats.tx_errors++; | ||
718 | |||
719 | spin_lock_irqsave(&fep->lock, flags); | ||
720 | |||
721 | if (dev->flags & IFF_UP) { | ||
722 | (*fep->ops->stop)(dev); | ||
723 | (*fep->ops->restart)(dev); | ||
724 | } | ||
725 | |||
726 | wake = fep->tx_free && !(CBDR_SC(fep->cur_tx) & BD_ENET_TX_READY); | ||
727 | spin_unlock_irqrestore(&fep->lock, flags); | ||
728 | |||
729 | if (wake) | ||
730 | netif_wake_queue(dev); | ||
731 | } | ||
732 | |||
733 | static int fs_enet_open(struct net_device *dev) | ||
734 | { | ||
735 | struct fs_enet_private *fep = netdev_priv(dev); | ||
736 | const struct fs_platform_info *fpi = fep->fpi; | ||
737 | int r; | ||
738 | |||
739 | /* Install our interrupt handler. */ | ||
740 | r = fs_request_irq(dev, fep->interrupt, "fs_enet-mac", fs_enet_interrupt); | ||
741 | if (r != 0) { | ||
742 | printk(KERN_ERR DRV_MODULE_NAME | ||
743 | ": %s Could not allocate FEC IRQ!", dev->name); | ||
744 | return -EINVAL; | ||
745 | } | ||
746 | |||
747 | /* Install our phy interrupt handler */ | ||
748 | if (fpi->phy_irq != -1) { | ||
749 | |||
750 | r = fs_request_irq(dev, fpi->phy_irq, "fs_enet-phy", fs_mii_link_interrupt); | ||
751 | if (r != 0) { | ||
752 | printk(KERN_ERR DRV_MODULE_NAME | ||
753 | ": %s Could not allocate PHY IRQ!", dev->name); | ||
754 | fs_free_irq(dev, fep->interrupt); | ||
755 | return -EINVAL; | ||
756 | } | ||
757 | } | ||
758 | |||
759 | fs_mii_startup(dev); | ||
760 | netif_carrier_off(dev); | ||
761 | fs_mii_link_status_change_check(dev, 1); | ||
762 | |||
763 | return 0; | ||
764 | } | ||
765 | |||
766 | static int fs_enet_close(struct net_device *dev) | ||
767 | { | ||
768 | struct fs_enet_private *fep = netdev_priv(dev); | ||
769 | const struct fs_platform_info *fpi = fep->fpi; | ||
770 | unsigned long flags; | ||
771 | |||
772 | netif_stop_queue(dev); | ||
773 | netif_carrier_off(dev); | ||
774 | fs_mii_shutdown(dev); | ||
775 | |||
776 | spin_lock_irqsave(&fep->lock, flags); | ||
777 | (*fep->ops->stop)(dev); | ||
778 | spin_unlock_irqrestore(&fep->lock, flags); | ||
779 | |||
780 | /* release any irqs */ | ||
781 | if (fpi->phy_irq != -1) | ||
782 | fs_free_irq(dev, fpi->phy_irq); | ||
783 | fs_free_irq(dev, fep->interrupt); | ||
784 | |||
785 | return 0; | ||
786 | } | ||
787 | |||
788 | static struct net_device_stats *fs_enet_get_stats(struct net_device *dev) | ||
789 | { | ||
790 | struct fs_enet_private *fep = netdev_priv(dev); | ||
791 | return &fep->stats; | ||
792 | } | ||
793 | |||
794 | /*************************************************************************/ | ||
795 | |||
796 | static void fs_get_drvinfo(struct net_device *dev, | ||
797 | struct ethtool_drvinfo *info) | ||
798 | { | ||
799 | strcpy(info->driver, DRV_MODULE_NAME); | ||
800 | strcpy(info->version, DRV_MODULE_VERSION); | ||
801 | } | ||
802 | |||
803 | static int fs_get_regs_len(struct net_device *dev) | ||
804 | { | ||
805 | struct fs_enet_private *fep = netdev_priv(dev); | ||
806 | |||
807 | return (*fep->ops->get_regs_len)(dev); | ||
808 | } | ||
809 | |||
810 | static void fs_get_regs(struct net_device *dev, struct ethtool_regs *regs, | ||
811 | void *p) | ||
812 | { | ||
813 | struct fs_enet_private *fep = netdev_priv(dev); | ||
814 | unsigned long flags; | ||
815 | int r, len; | ||
816 | |||
817 | len = regs->len; | ||
818 | |||
819 | spin_lock_irqsave(&fep->lock, flags); | ||
820 | r = (*fep->ops->get_regs)(dev, p, &len); | ||
821 | spin_unlock_irqrestore(&fep->lock, flags); | ||
822 | |||
823 | if (r == 0) | ||
824 | regs->version = 0; | ||
825 | } | ||
826 | |||
827 | static int fs_get_settings(struct net_device *dev, struct ethtool_cmd *cmd) | ||
828 | { | ||
829 | struct fs_enet_private *fep = netdev_priv(dev); | ||
830 | unsigned long flags; | ||
831 | int rc; | ||
832 | |||
833 | spin_lock_irqsave(&fep->lock, flags); | ||
834 | rc = mii_ethtool_gset(&fep->mii_if, cmd); | ||
835 | spin_unlock_irqrestore(&fep->lock, flags); | ||
836 | |||
837 | return rc; | ||
838 | } | ||
839 | |||
840 | static int fs_set_settings(struct net_device *dev, struct ethtool_cmd *cmd) | ||
841 | { | ||
842 | struct fs_enet_private *fep = netdev_priv(dev); | ||
843 | unsigned long flags; | ||
844 | int rc; | ||
845 | |||
846 | spin_lock_irqsave(&fep->lock, flags); | ||
847 | rc = mii_ethtool_sset(&fep->mii_if, cmd); | ||
848 | spin_unlock_irqrestore(&fep->lock, flags); | ||
849 | |||
850 | return rc; | ||
851 | } | ||
852 | |||
853 | static int fs_nway_reset(struct net_device *dev) | ||
854 | { | ||
855 | struct fs_enet_private *fep = netdev_priv(dev); | ||
856 | return mii_nway_restart(&fep->mii_if); | ||
857 | } | ||
858 | |||
859 | static u32 fs_get_msglevel(struct net_device *dev) | ||
860 | { | ||
861 | struct fs_enet_private *fep = netdev_priv(dev); | ||
862 | return fep->msg_enable; | ||
863 | } | ||
864 | |||
865 | static void fs_set_msglevel(struct net_device *dev, u32 value) | ||
866 | { | ||
867 | struct fs_enet_private *fep = netdev_priv(dev); | ||
868 | fep->msg_enable = value; | ||
869 | } | ||
870 | |||
871 | static struct ethtool_ops fs_ethtool_ops = { | ||
872 | .get_drvinfo = fs_get_drvinfo, | ||
873 | .get_regs_len = fs_get_regs_len, | ||
874 | .get_settings = fs_get_settings, | ||
875 | .set_settings = fs_set_settings, | ||
876 | .nway_reset = fs_nway_reset, | ||
877 | .get_link = ethtool_op_get_link, | ||
878 | .get_msglevel = fs_get_msglevel, | ||
879 | .set_msglevel = fs_set_msglevel, | ||
880 | .get_tx_csum = ethtool_op_get_tx_csum, | ||
881 | .set_tx_csum = ethtool_op_set_tx_csum, /* local! */ | ||
882 | .get_sg = ethtool_op_get_sg, | ||
883 | .set_sg = ethtool_op_set_sg, | ||
884 | .get_regs = fs_get_regs, | ||
885 | }; | ||
886 | |||
887 | static int fs_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) | ||
888 | { | ||
889 | struct fs_enet_private *fep = netdev_priv(dev); | ||
890 | struct mii_ioctl_data *mii = (struct mii_ioctl_data *)&rq->ifr_data; | ||
891 | unsigned long flags; | ||
892 | int rc; | ||
893 | |||
894 | if (!netif_running(dev)) | ||
895 | return -EINVAL; | ||
896 | |||
897 | spin_lock_irqsave(&fep->lock, flags); | ||
898 | rc = generic_mii_ioctl(&fep->mii_if, mii, cmd, NULL); | ||
899 | spin_unlock_irqrestore(&fep->lock, flags); | ||
900 | return rc; | ||
901 | } | ||
902 | |||
903 | extern int fs_mii_connect(struct net_device *dev); | ||
904 | extern void fs_mii_disconnect(struct net_device *dev); | ||
905 | |||
906 | static struct net_device *fs_init_instance(struct device *dev, | ||
907 | const struct fs_platform_info *fpi) | ||
908 | { | ||
909 | struct net_device *ndev = NULL; | ||
910 | struct fs_enet_private *fep = NULL; | ||
911 | int privsize, i, r, err = 0, registered = 0; | ||
912 | |||
913 | /* guard */ | ||
914 | if ((unsigned int)fpi->fs_no >= FS_MAX_INDEX) | ||
915 | return ERR_PTR(-EINVAL); | ||
916 | |||
917 | privsize = sizeof(*fep) + (sizeof(struct sk_buff **) * | ||
918 | (fpi->rx_ring + fpi->tx_ring)); | ||
919 | |||
920 | ndev = alloc_etherdev(privsize); | ||
921 | if (!ndev) { | ||
922 | err = -ENOMEM; | ||
923 | goto err; | ||
924 | } | ||
925 | SET_MODULE_OWNER(ndev); | ||
926 | |||
927 | fep = netdev_priv(ndev); | ||
928 | memset(fep, 0, privsize); /* clear everything */ | ||
929 | |||
930 | fep->dev = dev; | ||
931 | dev_set_drvdata(dev, ndev); | ||
932 | fep->fpi = fpi; | ||
933 | if (fpi->init_ioports) | ||
934 | fpi->init_ioports(); | ||
935 | |||
936 | #ifdef CONFIG_FS_ENET_HAS_FEC | ||
937 | if (fs_get_fec_index(fpi->fs_no) >= 0) | ||
938 | fep->ops = &fs_fec_ops; | ||
939 | #endif | ||
940 | |||
941 | #ifdef CONFIG_FS_ENET_HAS_SCC | ||
942 | if (fs_get_scc_index(fpi->fs_no) >=0 ) | ||
943 | fep->ops = &fs_scc_ops; | ||
944 | #endif | ||
945 | |||
946 | #ifdef CONFIG_FS_ENET_HAS_FCC | ||
947 | if (fs_get_fcc_index(fpi->fs_no) >= 0) | ||
948 | fep->ops = &fs_fcc_ops; | ||
949 | #endif | ||
950 | |||
951 | if (fep->ops == NULL) { | ||
952 | printk(KERN_ERR DRV_MODULE_NAME | ||
953 | ": %s No matching ops found (%d).\n", | ||
954 | ndev->name, fpi->fs_no); | ||
955 | err = -EINVAL; | ||
956 | goto err; | ||
957 | } | ||
958 | |||
959 | r = (*fep->ops->setup_data)(ndev); | ||
960 | if (r != 0) { | ||
961 | printk(KERN_ERR DRV_MODULE_NAME | ||
962 | ": %s setup_data failed\n", | ||
963 | ndev->name); | ||
964 | err = r; | ||
965 | goto err; | ||
966 | } | ||
967 | |||
968 | /* point rx_skbuff, tx_skbuff */ | ||
969 | fep->rx_skbuff = (struct sk_buff **)&fep[1]; | ||
970 | fep->tx_skbuff = fep->rx_skbuff + fpi->rx_ring; | ||
971 | |||
972 | /* init locks */ | ||
973 | spin_lock_init(&fep->lock); | ||
974 | spin_lock_init(&fep->tx_lock); | ||
975 | |||
976 | /* | ||
977 | * Set the Ethernet address. | ||
978 | */ | ||
979 | for (i = 0; i < 6; i++) | ||
980 | ndev->dev_addr[i] = fpi->macaddr[i]; | ||
981 | |||
982 | r = (*fep->ops->allocate_bd)(ndev); | ||
983 | |||
984 | if (fep->ring_base == NULL) { | ||
985 | printk(KERN_ERR DRV_MODULE_NAME | ||
986 | ": %s buffer descriptor alloc failed (%d).\n", ndev->name, r); | ||
987 | err = r; | ||
988 | goto err; | ||
989 | } | ||
990 | |||
991 | /* | ||
992 | * Set receive and transmit descriptor base. | ||
993 | */ | ||
994 | fep->rx_bd_base = fep->ring_base; | ||
995 | fep->tx_bd_base = fep->rx_bd_base + fpi->rx_ring; | ||
996 | |||
997 | /* initialize ring size variables */ | ||
998 | fep->tx_ring = fpi->tx_ring; | ||
999 | fep->rx_ring = fpi->rx_ring; | ||
1000 | |||
1001 | /* | ||
1002 | * The FEC Ethernet specific entries in the device structure. | ||
1003 | */ | ||
1004 | ndev->open = fs_enet_open; | ||
1005 | ndev->hard_start_xmit = fs_enet_start_xmit; | ||
1006 | ndev->tx_timeout = fs_timeout; | ||
1007 | ndev->watchdog_timeo = 2 * HZ; | ||
1008 | ndev->stop = fs_enet_close; | ||
1009 | ndev->get_stats = fs_enet_get_stats; | ||
1010 | ndev->set_multicast_list = fs_set_multicast_list; | ||
1011 | if (fpi->use_napi) { | ||
1012 | ndev->poll = fs_enet_rx_napi; | ||
1013 | ndev->weight = fpi->napi_weight; | ||
1014 | } | ||
1015 | ndev->ethtool_ops = &fs_ethtool_ops; | ||
1016 | ndev->do_ioctl = fs_ioctl; | ||
1017 | |||
1018 | init_timer(&fep->phy_timer_list); | ||
1019 | |||
1020 | netif_carrier_off(ndev); | ||
1021 | |||
1022 | err = register_netdev(ndev); | ||
1023 | if (err != 0) { | ||
1024 | printk(KERN_ERR DRV_MODULE_NAME | ||
1025 | ": %s register_netdev failed.\n", ndev->name); | ||
1026 | goto err; | ||
1027 | } | ||
1028 | registered = 1; | ||
1029 | |||
1030 | err = fs_mii_connect(ndev); | ||
1031 | if (err != 0) { | ||
1032 | printk(KERN_ERR DRV_MODULE_NAME | ||
1033 | ": %s fs_mii_connect failed.\n", ndev->name); | ||
1034 | goto err; | ||
1035 | } | ||
1036 | |||
1037 | return ndev; | ||
1038 | |||
1039 | err: | ||
1040 | if (ndev != NULL) { | ||
1041 | |||
1042 | if (registered) | ||
1043 | unregister_netdev(ndev); | ||
1044 | |||
1045 | if (fep != NULL) { | ||
1046 | (*fep->ops->free_bd)(ndev); | ||
1047 | (*fep->ops->cleanup_data)(ndev); | ||
1048 | } | ||
1049 | |||
1050 | free_netdev(ndev); | ||
1051 | } | ||
1052 | |||
1053 | dev_set_drvdata(dev, NULL); | ||
1054 | |||
1055 | return ERR_PTR(err); | ||
1056 | } | ||
1057 | |||
1058 | static int fs_cleanup_instance(struct net_device *ndev) | ||
1059 | { | ||
1060 | struct fs_enet_private *fep; | ||
1061 | const struct fs_platform_info *fpi; | ||
1062 | struct device *dev; | ||
1063 | |||
1064 | if (ndev == NULL) | ||
1065 | return -EINVAL; | ||
1066 | |||
1067 | fep = netdev_priv(ndev); | ||
1068 | if (fep == NULL) | ||
1069 | return -EINVAL; | ||
1070 | |||
1071 | fpi = fep->fpi; | ||
1072 | |||
1073 | fs_mii_disconnect(ndev); | ||
1074 | |||
1075 | unregister_netdev(ndev); | ||
1076 | |||
1077 | dma_free_coherent(fep->dev, (fpi->tx_ring + fpi->rx_ring) * sizeof(cbd_t), | ||
1078 | fep->ring_base, fep->ring_mem_addr); | ||
1079 | |||
1080 | /* reset it */ | ||
1081 | (*fep->ops->cleanup_data)(ndev); | ||
1082 | |||
1083 | dev = fep->dev; | ||
1084 | if (dev != NULL) { | ||
1085 | dev_set_drvdata(dev, NULL); | ||
1086 | fep->dev = NULL; | ||
1087 | } | ||
1088 | |||
1089 | free_netdev(ndev); | ||
1090 | |||
1091 | return 0; | ||
1092 | } | ||
1093 | |||
1094 | /**************************************************************************************/ | ||
1095 | |||
1096 | /* handy pointer to the immap */ | ||
1097 | void *fs_enet_immap = NULL; | ||
1098 | |||
1099 | static int setup_immap(void) | ||
1100 | { | ||
1101 | phys_addr_t paddr = 0; | ||
1102 | unsigned long size = 0; | ||
1103 | |||
1104 | #ifdef CONFIG_CPM1 | ||
1105 | paddr = IMAP_ADDR; | ||
1106 | size = 0x10000; /* map 64K */ | ||
1107 | #endif | ||
1108 | |||
1109 | #ifdef CONFIG_CPM2 | ||
1110 | paddr = CPM_MAP_ADDR; | ||
1111 | size = 0x40000; /* map 256 K */ | ||
1112 | #endif | ||
1113 | fs_enet_immap = ioremap(paddr, size); | ||
1114 | if (fs_enet_immap == NULL) | ||
1115 | return -EBADF; /* XXX ahem; maybe just BUG_ON? */ | ||
1116 | |||
1117 | return 0; | ||
1118 | } | ||
1119 | |||
1120 | static void cleanup_immap(void) | ||
1121 | { | ||
1122 | if (fs_enet_immap != NULL) { | ||
1123 | iounmap(fs_enet_immap); | ||
1124 | fs_enet_immap = NULL; | ||
1125 | } | ||
1126 | } | ||
1127 | |||
1128 | /**************************************************************************************/ | ||
1129 | |||
1130 | static int __devinit fs_enet_probe(struct device *dev) | ||
1131 | { | ||
1132 | struct net_device *ndev; | ||
1133 | |||
1134 | /* no fixup - no device */ | ||
1135 | if (dev->platform_data == NULL) { | ||
1136 | printk(KERN_INFO "fs_enet: " | ||
1137 | "probe called with no platform data; " | ||
1138 | "remove unused devices\n"); | ||
1139 | return -ENODEV; | ||
1140 | } | ||
1141 | |||
1142 | ndev = fs_init_instance(dev, dev->platform_data); | ||
1143 | if (IS_ERR(ndev)) | ||
1144 | return PTR_ERR(ndev); | ||
1145 | return 0; | ||
1146 | } | ||
1147 | |||
1148 | static int fs_enet_remove(struct device *dev) | ||
1149 | { | ||
1150 | return fs_cleanup_instance(dev_get_drvdata(dev)); | ||
1151 | } | ||
1152 | |||
1153 | static struct device_driver fs_enet_fec_driver = { | ||
1154 | .name = "fsl-cpm-fec", | ||
1155 | .bus = &platform_bus_type, | ||
1156 | .probe = fs_enet_probe, | ||
1157 | .remove = fs_enet_remove, | ||
1158 | #ifdef CONFIG_PM | ||
1159 | /* .suspend = fs_enet_suspend, TODO */ | ||
1160 | /* .resume = fs_enet_resume, TODO */ | ||
1161 | #endif | ||
1162 | }; | ||
1163 | |||
1164 | static struct device_driver fs_enet_scc_driver = { | ||
1165 | .name = "fsl-cpm-scc", | ||
1166 | .bus = &platform_bus_type, | ||
1167 | .probe = fs_enet_probe, | ||
1168 | .remove = fs_enet_remove, | ||
1169 | #ifdef CONFIG_PM | ||
1170 | /* .suspend = fs_enet_suspend, TODO */ | ||
1171 | /* .resume = fs_enet_resume, TODO */ | ||
1172 | #endif | ||
1173 | }; | ||
1174 | |||
1175 | static struct device_driver fs_enet_fcc_driver = { | ||
1176 | .name = "fsl-cpm-fcc", | ||
1177 | .bus = &platform_bus_type, | ||
1178 | .probe = fs_enet_probe, | ||
1179 | .remove = fs_enet_remove, | ||
1180 | #ifdef CONFIG_PM | ||
1181 | /* .suspend = fs_enet_suspend, TODO */ | ||
1182 | /* .resume = fs_enet_resume, TODO */ | ||
1183 | #endif | ||
1184 | }; | ||
1185 | |||
1186 | static int __init fs_init(void) | ||
1187 | { | ||
1188 | int r; | ||
1189 | |||
1190 | printk(KERN_INFO | ||
1191 | "%s", version); | ||
1192 | |||
1193 | r = setup_immap(); | ||
1194 | if (r != 0) | ||
1195 | return r; | ||
1196 | r = driver_register(&fs_enet_fec_driver); | ||
1197 | if (r != 0) | ||
1198 | goto err; | ||
1199 | |||
1200 | r = driver_register(&fs_enet_fcc_driver); | ||
1201 | if (r != 0) | ||
1202 | goto err; | ||
1203 | |||
1204 | r = driver_register(&fs_enet_scc_driver); | ||
1205 | if (r != 0) | ||
1206 | goto err; | ||
1207 | |||
1208 | return 0; | ||
1209 | err: | ||
1210 | cleanup_immap(); | ||
1211 | return r; | ||
1212 | |||
1213 | } | ||
1214 | |||
1215 | static void __exit fs_cleanup(void) | ||
1216 | { | ||
1217 | driver_unregister(&fs_enet_fec_driver); | ||
1218 | driver_unregister(&fs_enet_fcc_driver); | ||
1219 | driver_unregister(&fs_enet_scc_driver); | ||
1220 | cleanup_immap(); | ||
1221 | } | ||
1222 | |||
1223 | /**************************************************************************************/ | ||
1224 | |||
1225 | module_init(fs_init); | ||
1226 | module_exit(fs_cleanup); | ||
diff --git a/drivers/net/fs_enet/fs_enet-mii.c b/drivers/net/fs_enet/fs_enet-mii.c new file mode 100644 index 000000000000..c6770377ef87 --- /dev/null +++ b/drivers/net/fs_enet/fs_enet-mii.c | |||
@@ -0,0 +1,507 @@ | |||
1 | /* | ||
2 | * Combined Ethernet driver for Motorola MPC8xx and MPC82xx. | ||
3 | * | ||
4 | * Copyright (c) 2003 Intracom S.A. | ||
5 | * by Pantelis Antoniou <panto@intracom.gr> | ||
6 | * | ||
7 | * 2005 (c) MontaVista Software, Inc. | ||
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 | * | ||
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 | ||
15 | * kind, whether express or implied. | ||
16 | */ | ||
17 | |||
18 | |||
19 | #include <linux/config.h> | ||
20 | #include <linux/module.h> | ||
21 | #include <linux/types.h> | ||
22 | #include <linux/kernel.h> | ||
23 | #include <linux/sched.h> | ||
24 | #include <linux/string.h> | ||
25 | #include <linux/ptrace.h> | ||
26 | #include <linux/errno.h> | ||
27 | #include <linux/ioport.h> | ||
28 | #include <linux/slab.h> | ||
29 | #include <linux/interrupt.h> | ||
30 | #include <linux/pci.h> | ||
31 | #include <linux/init.h> | ||
32 | #include <linux/delay.h> | ||
33 | #include <linux/netdevice.h> | ||
34 | #include <linux/etherdevice.h> | ||
35 | #include <linux/skbuff.h> | ||
36 | #include <linux/spinlock.h> | ||
37 | #include <linux/mii.h> | ||
38 | #include <linux/ethtool.h> | ||
39 | #include <linux/bitops.h> | ||
40 | |||
41 | #include <asm/pgtable.h> | ||
42 | #include <asm/irq.h> | ||
43 | #include <asm/uaccess.h> | ||
44 | |||
45 | #include "fs_enet.h" | ||
46 | |||
47 | /*************************************************/ | ||
48 | |||
49 | /* | ||
50 | * Generic PHY support. | ||
51 | * Should work for all PHYs, but link change is detected by polling | ||
52 | */ | ||
53 | |||
54 | static void generic_timer_callback(unsigned long data) | ||
55 | { | ||
56 | struct net_device *dev = (struct net_device *)data; | ||
57 | struct fs_enet_private *fep = netdev_priv(dev); | ||
58 | |||
59 | fep->phy_timer_list.expires = jiffies + HZ / 2; | ||
60 | |||
61 | add_timer(&fep->phy_timer_list); | ||
62 | |||
63 | fs_mii_link_status_change_check(dev, 0); | ||
64 | } | ||
65 | |||
66 | static void generic_startup(struct net_device *dev) | ||
67 | { | ||
68 | struct fs_enet_private *fep = netdev_priv(dev); | ||
69 | |||
70 | fep->phy_timer_list.expires = jiffies + HZ / 2; /* every 500ms */ | ||
71 | fep->phy_timer_list.data = (unsigned long)dev; | ||
72 | fep->phy_timer_list.function = generic_timer_callback; | ||
73 | add_timer(&fep->phy_timer_list); | ||
74 | } | ||
75 | |||
76 | static void generic_shutdown(struct net_device *dev) | ||
77 | { | ||
78 | struct fs_enet_private *fep = netdev_priv(dev); | ||
79 | |||
80 | del_timer_sync(&fep->phy_timer_list); | ||
81 | } | ||
82 | |||
83 | /* ------------------------------------------------------------------------- */ | ||
84 | /* The Davicom DM9161 is used on the NETTA board */ | ||
85 | |||
86 | /* register definitions */ | ||
87 | |||
88 | #define MII_DM9161_ANAR 4 /* Aux. Config Register */ | ||
89 | #define MII_DM9161_ACR 16 /* Aux. Config Register */ | ||
90 | #define MII_DM9161_ACSR 17 /* Aux. Config/Status Register */ | ||
91 | #define MII_DM9161_10TCSR 18 /* 10BaseT Config/Status Reg. */ | ||
92 | #define MII_DM9161_INTR 21 /* Interrupt Register */ | ||
93 | #define MII_DM9161_RECR 22 /* Receive Error Counter Reg. */ | ||
94 | #define MII_DM9161_DISCR 23 /* Disconnect Counter Register */ | ||
95 | |||
96 | static void dm9161_startup(struct net_device *dev) | ||
97 | { | ||
98 | struct fs_enet_private *fep = netdev_priv(dev); | ||
99 | |||
100 | fs_mii_write(dev, fep->mii_if.phy_id, MII_DM9161_INTR, 0x0000); | ||
101 | /* Start autonegotiation */ | ||
102 | fs_mii_write(dev, fep->mii_if.phy_id, MII_BMCR, 0x1200); | ||
103 | |||
104 | set_current_state(TASK_UNINTERRUPTIBLE); | ||
105 | schedule_timeout(HZ*8); | ||
106 | } | ||
107 | |||
108 | static void dm9161_ack_int(struct net_device *dev) | ||
109 | { | ||
110 | struct fs_enet_private *fep = netdev_priv(dev); | ||
111 | |||
112 | fs_mii_read(dev, fep->mii_if.phy_id, MII_DM9161_INTR); | ||
113 | } | ||
114 | |||
115 | static void dm9161_shutdown(struct net_device *dev) | ||
116 | { | ||
117 | struct fs_enet_private *fep = netdev_priv(dev); | ||
118 | |||
119 | fs_mii_write(dev, fep->mii_if.phy_id, MII_DM9161_INTR, 0x0f00); | ||
120 | } | ||
121 | |||
122 | /**********************************************************************************/ | ||
123 | |||
124 | static const struct phy_info phy_info[] = { | ||
125 | { | ||
126 | .id = 0x00181b88, | ||
127 | .name = "DM9161", | ||
128 | .startup = dm9161_startup, | ||
129 | .ack_int = dm9161_ack_int, | ||
130 | .shutdown = dm9161_shutdown, | ||
131 | }, { | ||
132 | .id = 0, | ||
133 | .name = "GENERIC", | ||
134 | .startup = generic_startup, | ||
135 | .shutdown = generic_shutdown, | ||
136 | }, | ||
137 | }; | ||
138 | |||
139 | /**********************************************************************************/ | ||
140 | |||
141 | static int phy_id_detect(struct net_device *dev) | ||
142 | { | ||
143 | struct fs_enet_private *fep = netdev_priv(dev); | ||
144 | const struct fs_platform_info *fpi = fep->fpi; | ||
145 | struct fs_enet_mii_bus *bus = fep->mii_bus; | ||
146 | int i, r, start, end, phytype, physubtype; | ||
147 | const struct phy_info *phy; | ||
148 | int phy_hwid, phy_id; | ||
149 | |||
150 | phy_hwid = -1; | ||
151 | fep->phy = NULL; | ||
152 | |||
153 | /* auto-detect? */ | ||
154 | if (fpi->phy_addr == -1) { | ||
155 | start = 1; | ||
156 | end = 32; | ||
157 | } else { /* direct */ | ||
158 | start = fpi->phy_addr; | ||
159 | end = start + 1; | ||
160 | } | ||
161 | |||
162 | for (phy_id = start; phy_id < end; phy_id++) { | ||
163 | /* skip already used phy addresses on this bus */ | ||
164 | if (bus->usage_map & (1 << phy_id)) | ||
165 | continue; | ||
166 | r = fs_mii_read(dev, phy_id, MII_PHYSID1); | ||
167 | if (r == -1 || (phytype = (r & 0xffff)) == 0xffff) | ||
168 | continue; | ||
169 | r = fs_mii_read(dev, phy_id, MII_PHYSID2); | ||
170 | if (r == -1 || (physubtype = (r & 0xffff)) == 0xffff) | ||
171 | continue; | ||
172 | phy_hwid = (phytype << 16) | physubtype; | ||
173 | if (phy_hwid != -1) | ||
174 | break; | ||
175 | } | ||
176 | |||
177 | if (phy_hwid == -1) { | ||
178 | printk(KERN_ERR DRV_MODULE_NAME | ||
179 | ": %s No PHY detected! range=0x%02x-0x%02x\n", | ||
180 | dev->name, start, end); | ||
181 | return -1; | ||
182 | } | ||
183 | |||
184 | for (i = 0, phy = phy_info; i < ARRAY_SIZE(phy_info); i++, phy++) | ||
185 | if (phy->id == (phy_hwid >> 4) || phy->id == 0) | ||
186 | break; | ||
187 | |||
188 | if (i >= ARRAY_SIZE(phy_info)) { | ||
189 | printk(KERN_ERR DRV_MODULE_NAME | ||
190 | ": %s PHY id 0x%08x is not supported!\n", | ||
191 | dev->name, phy_hwid); | ||
192 | return -1; | ||
193 | } | ||
194 | |||
195 | fep->phy = phy; | ||
196 | |||
197 | /* mark this address as used */ | ||
198 | bus->usage_map |= (1 << phy_id); | ||
199 | |||
200 | printk(KERN_INFO DRV_MODULE_NAME | ||
201 | ": %s Phy @ 0x%x, type %s (0x%08x)%s\n", | ||
202 | dev->name, phy_id, fep->phy->name, phy_hwid, | ||
203 | fpi->phy_addr == -1 ? " (auto-detected)" : ""); | ||
204 | |||
205 | return phy_id; | ||
206 | } | ||
207 | |||
208 | void fs_mii_startup(struct net_device *dev) | ||
209 | { | ||
210 | struct fs_enet_private *fep = netdev_priv(dev); | ||
211 | |||
212 | if (fep->phy->startup) | ||
213 | (*fep->phy->startup) (dev); | ||
214 | } | ||
215 | |||
216 | void fs_mii_shutdown(struct net_device *dev) | ||
217 | { | ||
218 | struct fs_enet_private *fep = netdev_priv(dev); | ||
219 | |||
220 | if (fep->phy->shutdown) | ||
221 | (*fep->phy->shutdown) (dev); | ||
222 | } | ||
223 | |||
224 | void fs_mii_ack_int(struct net_device *dev) | ||
225 | { | ||
226 | struct fs_enet_private *fep = netdev_priv(dev); | ||
227 | |||
228 | if (fep->phy->ack_int) | ||
229 | (*fep->phy->ack_int) (dev); | ||
230 | } | ||
231 | |||
232 | #define MII_LINK 0x0001 | ||
233 | #define MII_HALF 0x0002 | ||
234 | #define MII_FULL 0x0004 | ||
235 | #define MII_BASE4 0x0008 | ||
236 | #define MII_10M 0x0010 | ||
237 | #define MII_100M 0x0020 | ||
238 | #define MII_1G 0x0040 | ||
239 | #define MII_10G 0x0080 | ||
240 | |||
241 | /* return full mii info at one gulp, with a usable form */ | ||
242 | static unsigned int mii_full_status(struct mii_if_info *mii) | ||
243 | { | ||
244 | unsigned int status; | ||
245 | int bmsr, adv, lpa, neg; | ||
246 | struct fs_enet_private* fep = netdev_priv(mii->dev); | ||
247 | |||
248 | /* first, a dummy read, needed to latch some MII phys */ | ||
249 | (void)mii->mdio_read(mii->dev, mii->phy_id, MII_BMSR); | ||
250 | bmsr = mii->mdio_read(mii->dev, mii->phy_id, MII_BMSR); | ||
251 | |||
252 | /* no link */ | ||
253 | if ((bmsr & BMSR_LSTATUS) == 0) | ||
254 | return 0; | ||
255 | |||
256 | status = MII_LINK; | ||
257 | |||
258 | /* Lets look what ANEG says if it's supported - otherwize we shall | ||
259 | take the right values from the platform info*/ | ||
260 | if(!mii->force_media) { | ||
261 | /* autoneg not completed; don't bother */ | ||
262 | if ((bmsr & BMSR_ANEGCOMPLETE) == 0) | ||
263 | return 0; | ||
264 | |||
265 | adv = (*mii->mdio_read)(mii->dev, mii->phy_id, MII_ADVERTISE); | ||
266 | lpa = (*mii->mdio_read)(mii->dev, mii->phy_id, MII_LPA); | ||
267 | |||
268 | neg = lpa & adv; | ||
269 | } else { | ||
270 | neg = fep->fpi->bus_info->lpa; | ||
271 | } | ||
272 | |||
273 | if (neg & LPA_100FULL) | ||
274 | status |= MII_FULL | MII_100M; | ||
275 | else if (neg & LPA_100BASE4) | ||
276 | status |= MII_FULL | MII_BASE4 | MII_100M; | ||
277 | else if (neg & LPA_100HALF) | ||
278 | status |= MII_HALF | MII_100M; | ||
279 | else if (neg & LPA_10FULL) | ||
280 | status |= MII_FULL | MII_10M; | ||
281 | else | ||
282 | status |= MII_HALF | MII_10M; | ||
283 | |||
284 | return status; | ||
285 | } | ||
286 | |||
287 | void fs_mii_link_status_change_check(struct net_device *dev, int init_media) | ||
288 | { | ||
289 | struct fs_enet_private *fep = netdev_priv(dev); | ||
290 | struct mii_if_info *mii = &fep->mii_if; | ||
291 | unsigned int mii_status; | ||
292 | int ok_to_print, link, duplex, speed; | ||
293 | unsigned long flags; | ||
294 | |||
295 | ok_to_print = netif_msg_link(fep); | ||
296 | |||
297 | mii_status = mii_full_status(mii); | ||
298 | |||
299 | if (!init_media && mii_status == fep->last_mii_status) | ||
300 | return; | ||
301 | |||
302 | fep->last_mii_status = mii_status; | ||
303 | |||
304 | link = !!(mii_status & MII_LINK); | ||
305 | duplex = !!(mii_status & MII_FULL); | ||
306 | speed = (mii_status & MII_100M) ? 100 : 10; | ||
307 | |||
308 | if (link == 0) { | ||
309 | netif_carrier_off(mii->dev); | ||
310 | netif_stop_queue(dev); | ||
311 | if (!init_media) { | ||
312 | spin_lock_irqsave(&fep->lock, flags); | ||
313 | (*fep->ops->stop)(dev); | ||
314 | spin_unlock_irqrestore(&fep->lock, flags); | ||
315 | } | ||
316 | |||
317 | if (ok_to_print) | ||
318 | printk(KERN_INFO "%s: link down\n", mii->dev->name); | ||
319 | |||
320 | } else { | ||
321 | |||
322 | mii->full_duplex = duplex; | ||
323 | |||
324 | netif_carrier_on(mii->dev); | ||
325 | |||
326 | spin_lock_irqsave(&fep->lock, flags); | ||
327 | fep->duplex = duplex; | ||
328 | fep->speed = speed; | ||
329 | (*fep->ops->restart)(dev); | ||
330 | spin_unlock_irqrestore(&fep->lock, flags); | ||
331 | |||
332 | netif_start_queue(dev); | ||
333 | |||
334 | if (ok_to_print) | ||
335 | printk(KERN_INFO "%s: link up, %dMbps, %s-duplex\n", | ||
336 | dev->name, speed, duplex ? "full" : "half"); | ||
337 | } | ||
338 | } | ||
339 | |||
340 | /**********************************************************************************/ | ||
341 | |||
342 | int fs_mii_read(struct net_device *dev, int phy_id, int location) | ||
343 | { | ||
344 | struct fs_enet_private *fep = netdev_priv(dev); | ||
345 | struct fs_enet_mii_bus *bus = fep->mii_bus; | ||
346 | |||
347 | unsigned long flags; | ||
348 | int ret; | ||
349 | |||
350 | spin_lock_irqsave(&bus->mii_lock, flags); | ||
351 | ret = (*bus->mii_read)(bus, phy_id, location); | ||
352 | spin_unlock_irqrestore(&bus->mii_lock, flags); | ||
353 | |||
354 | return ret; | ||
355 | } | ||
356 | |||
357 | void fs_mii_write(struct net_device *dev, int phy_id, int location, int value) | ||
358 | { | ||
359 | struct fs_enet_private *fep = netdev_priv(dev); | ||
360 | struct fs_enet_mii_bus *bus = fep->mii_bus; | ||
361 | unsigned long flags; | ||
362 | |||
363 | spin_lock_irqsave(&bus->mii_lock, flags); | ||
364 | (*bus->mii_write)(bus, phy_id, location, value); | ||
365 | spin_unlock_irqrestore(&bus->mii_lock, flags); | ||
366 | } | ||
367 | |||
368 | /*****************************************************************************/ | ||
369 | |||
370 | /* list of all registered mii buses */ | ||
371 | static LIST_HEAD(fs_mii_bus_list); | ||
372 | |||
373 | static struct fs_enet_mii_bus *lookup_bus(int method, int id) | ||
374 | { | ||
375 | struct list_head *ptr; | ||
376 | struct fs_enet_mii_bus *bus; | ||
377 | |||
378 | list_for_each(ptr, &fs_mii_bus_list) { | ||
379 | bus = list_entry(ptr, struct fs_enet_mii_bus, list); | ||
380 | if (bus->bus_info->method == method && | ||
381 | bus->bus_info->id == id) | ||
382 | return bus; | ||
383 | } | ||
384 | return NULL; | ||
385 | } | ||
386 | |||
387 | static struct fs_enet_mii_bus *create_bus(const struct fs_mii_bus_info *bi) | ||
388 | { | ||
389 | struct fs_enet_mii_bus *bus; | ||
390 | int ret = 0; | ||
391 | |||
392 | bus = kmalloc(sizeof(*bus), GFP_KERNEL); | ||
393 | if (bus == NULL) { | ||
394 | ret = -ENOMEM; | ||
395 | goto err; | ||
396 | } | ||
397 | memset(bus, 0, sizeof(*bus)); | ||
398 | spin_lock_init(&bus->mii_lock); | ||
399 | bus->bus_info = bi; | ||
400 | bus->refs = 0; | ||
401 | bus->usage_map = 0; | ||
402 | |||
403 | /* perform initialization */ | ||
404 | switch (bi->method) { | ||
405 | |||
406 | case fsmii_fixed: | ||
407 | ret = fs_mii_fixed_init(bus); | ||
408 | if (ret != 0) | ||
409 | goto err; | ||
410 | break; | ||
411 | |||
412 | case fsmii_bitbang: | ||
413 | ret = fs_mii_bitbang_init(bus); | ||
414 | if (ret != 0) | ||
415 | goto err; | ||
416 | break; | ||
417 | #ifdef CONFIG_FS_ENET_HAS_FEC | ||
418 | case fsmii_fec: | ||
419 | ret = fs_mii_fec_init(bus); | ||
420 | if (ret != 0) | ||
421 | goto err; | ||
422 | break; | ||
423 | #endif | ||
424 | default: | ||
425 | ret = -EINVAL; | ||
426 | goto err; | ||
427 | } | ||
428 | |||
429 | list_add(&bus->list, &fs_mii_bus_list); | ||
430 | |||
431 | return bus; | ||
432 | |||
433 | err: | ||
434 | if (bus) | ||
435 | kfree(bus); | ||
436 | return ERR_PTR(ret); | ||
437 | } | ||
438 | |||
439 | static void destroy_bus(struct fs_enet_mii_bus *bus) | ||
440 | { | ||
441 | /* remove from bus list */ | ||
442 | list_del(&bus->list); | ||
443 | |||
444 | /* nothing more needed */ | ||
445 | kfree(bus); | ||
446 | } | ||
447 | |||
448 | int fs_mii_connect(struct net_device *dev) | ||
449 | { | ||
450 | struct fs_enet_private *fep = netdev_priv(dev); | ||
451 | const struct fs_platform_info *fpi = fep->fpi; | ||
452 | struct fs_enet_mii_bus *bus = NULL; | ||
453 | |||
454 | /* check method validity */ | ||
455 | switch (fpi->bus_info->method) { | ||
456 | case fsmii_fixed: | ||
457 | case fsmii_bitbang: | ||
458 | break; | ||
459 | #ifdef CONFIG_FS_ENET_HAS_FEC | ||
460 | case fsmii_fec: | ||
461 | break; | ||
462 | #endif | ||
463 | default: | ||
464 | printk(KERN_ERR DRV_MODULE_NAME | ||
465 | ": %s Unknown MII bus method (%d)!\n", | ||
466 | dev->name, fpi->bus_info->method); | ||
467 | return -EINVAL; | ||
468 | } | ||
469 | |||
470 | bus = lookup_bus(fpi->bus_info->method, fpi->bus_info->id); | ||
471 | |||
472 | /* if not found create new bus */ | ||
473 | if (bus == NULL) { | ||
474 | bus = create_bus(fpi->bus_info); | ||
475 | if (IS_ERR(bus)) { | ||
476 | printk(KERN_ERR DRV_MODULE_NAME | ||
477 | ": %s MII bus creation failure!\n", dev->name); | ||
478 | return PTR_ERR(bus); | ||
479 | } | ||
480 | } | ||
481 | |||
482 | bus->refs++; | ||
483 | |||
484 | fep->mii_bus = bus; | ||
485 | |||
486 | fep->mii_if.dev = dev; | ||
487 | fep->mii_if.phy_id_mask = 0x1f; | ||
488 | fep->mii_if.reg_num_mask = 0x1f; | ||
489 | fep->mii_if.mdio_read = fs_mii_read; | ||
490 | fep->mii_if.mdio_write = fs_mii_write; | ||
491 | fep->mii_if.force_media = fpi->bus_info->disable_aneg; | ||
492 | fep->mii_if.phy_id = phy_id_detect(dev); | ||
493 | |||
494 | return 0; | ||
495 | } | ||
496 | |||
497 | void fs_mii_disconnect(struct net_device *dev) | ||
498 | { | ||
499 | struct fs_enet_private *fep = netdev_priv(dev); | ||
500 | struct fs_enet_mii_bus *bus = NULL; | ||
501 | |||
502 | bus = fep->mii_bus; | ||
503 | fep->mii_bus = NULL; | ||
504 | |||
505 | if (--bus->refs <= 0) | ||
506 | destroy_bus(bus); | ||
507 | } | ||
diff --git a/drivers/net/fs_enet/fs_enet.h b/drivers/net/fs_enet/fs_enet.h new file mode 100644 index 000000000000..1105543b9d88 --- /dev/null +++ b/drivers/net/fs_enet/fs_enet.h | |||
@@ -0,0 +1,245 @@ | |||
1 | #ifndef FS_ENET_H | ||
2 | #define FS_ENET_H | ||
3 | |||
4 | #include <linux/mii.h> | ||
5 | #include <linux/netdevice.h> | ||
6 | #include <linux/types.h> | ||
7 | #include <linux/version.h> | ||
8 | #include <linux/list.h> | ||
9 | |||
10 | #include <linux/fs_enet_pd.h> | ||
11 | |||
12 | #include <asm/dma-mapping.h> | ||
13 | |||
14 | #ifdef CONFIG_CPM1 | ||
15 | #include <asm/commproc.h> | ||
16 | #endif | ||
17 | |||
18 | #ifdef CONFIG_CPM2 | ||
19 | #include <asm/cpm2.h> | ||
20 | #endif | ||
21 | |||
22 | /* hw driver ops */ | ||
23 | struct fs_ops { | ||
24 | int (*setup_data)(struct net_device *dev); | ||
25 | int (*allocate_bd)(struct net_device *dev); | ||
26 | void (*free_bd)(struct net_device *dev); | ||
27 | void (*cleanup_data)(struct net_device *dev); | ||
28 | void (*set_multicast_list)(struct net_device *dev); | ||
29 | void (*restart)(struct net_device *dev); | ||
30 | void (*stop)(struct net_device *dev); | ||
31 | void (*pre_request_irq)(struct net_device *dev, int irq); | ||
32 | void (*post_free_irq)(struct net_device *dev, int irq); | ||
33 | void (*napi_clear_rx_event)(struct net_device *dev); | ||
34 | void (*napi_enable_rx)(struct net_device *dev); | ||
35 | void (*napi_disable_rx)(struct net_device *dev); | ||
36 | void (*rx_bd_done)(struct net_device *dev); | ||
37 | void (*tx_kickstart)(struct net_device *dev); | ||
38 | u32 (*get_int_events)(struct net_device *dev); | ||
39 | void (*clear_int_events)(struct net_device *dev, u32 int_events); | ||
40 | void (*ev_error)(struct net_device *dev, u32 int_events); | ||
41 | int (*get_regs)(struct net_device *dev, void *p, int *sizep); | ||
42 | int (*get_regs_len)(struct net_device *dev); | ||
43 | void (*tx_restart)(struct net_device *dev); | ||
44 | }; | ||
45 | |||
46 | struct phy_info { | ||
47 | unsigned int id; | ||
48 | const char *name; | ||
49 | void (*startup) (struct net_device * dev); | ||
50 | void (*shutdown) (struct net_device * dev); | ||
51 | void (*ack_int) (struct net_device * dev); | ||
52 | }; | ||
53 | |||
54 | /* The FEC stores dest/src/type, data, and checksum for receive packets. | ||
55 | */ | ||
56 | #define MAX_MTU 1508 /* Allow fullsized pppoe packets over VLAN */ | ||
57 | #define MIN_MTU 46 /* this is data size */ | ||
58 | #define CRC_LEN 4 | ||
59 | |||
60 | #define PKT_MAXBUF_SIZE (MAX_MTU+ETH_HLEN+CRC_LEN) | ||
61 | #define PKT_MINBUF_SIZE (MIN_MTU+ETH_HLEN+CRC_LEN) | ||
62 | |||
63 | /* Must be a multiple of 32 (to cover both FEC & FCC) */ | ||
64 | #define PKT_MAXBLR_SIZE ((PKT_MAXBUF_SIZE + 31) & ~31) | ||
65 | /* This is needed so that invalidate_xxx wont invalidate too much */ | ||
66 | #define ENET_RX_FRSIZE L1_CACHE_ALIGN(PKT_MAXBUF_SIZE) | ||
67 | |||
68 | struct fs_enet_mii_bus { | ||
69 | struct list_head list; | ||
70 | spinlock_t mii_lock; | ||
71 | const struct fs_mii_bus_info *bus_info; | ||
72 | int refs; | ||
73 | u32 usage_map; | ||
74 | |||
75 | int (*mii_read)(struct fs_enet_mii_bus *bus, | ||
76 | int phy_id, int location); | ||
77 | |||
78 | void (*mii_write)(struct fs_enet_mii_bus *bus, | ||
79 | int phy_id, int location, int value); | ||
80 | |||
81 | union { | ||
82 | struct { | ||
83 | unsigned int mii_speed; | ||
84 | void *fecp; | ||
85 | } fec; | ||
86 | |||
87 | struct { | ||
88 | /* note that the actual port size may */ | ||
89 | /* be different; cpm(s) handle it OK */ | ||
90 | u8 mdio_msk; | ||
91 | u8 *mdio_dir; | ||
92 | u8 *mdio_dat; | ||
93 | u8 mdc_msk; | ||
94 | u8 *mdc_dir; | ||
95 | u8 *mdc_dat; | ||
96 | } bitbang; | ||
97 | |||
98 | struct { | ||
99 | u16 lpa; | ||
100 | } fixed; | ||
101 | }; | ||
102 | }; | ||
103 | |||
104 | int fs_mii_bitbang_init(struct fs_enet_mii_bus *bus); | ||
105 | int fs_mii_fixed_init(struct fs_enet_mii_bus *bus); | ||
106 | int fs_mii_fec_init(struct fs_enet_mii_bus *bus); | ||
107 | |||
108 | struct fs_enet_private { | ||
109 | struct device *dev; /* pointer back to the device (must be initialized first) */ | ||
110 | spinlock_t lock; /* during all ops except TX pckt processing */ | ||
111 | spinlock_t tx_lock; /* during fs_start_xmit and fs_tx */ | ||
112 | const struct fs_platform_info *fpi; | ||
113 | const struct fs_ops *ops; | ||
114 | int rx_ring, tx_ring; | ||
115 | dma_addr_t ring_mem_addr; | ||
116 | void *ring_base; | ||
117 | struct sk_buff **rx_skbuff; | ||
118 | struct sk_buff **tx_skbuff; | ||
119 | cbd_t *rx_bd_base; /* Address of Rx and Tx buffers. */ | ||
120 | cbd_t *tx_bd_base; | ||
121 | cbd_t *dirty_tx; /* ring entries to be free()ed. */ | ||
122 | cbd_t *cur_rx; | ||
123 | cbd_t *cur_tx; | ||
124 | int tx_free; | ||
125 | struct net_device_stats stats; | ||
126 | struct timer_list phy_timer_list; | ||
127 | const struct phy_info *phy; | ||
128 | u32 msg_enable; | ||
129 | struct mii_if_info mii_if; | ||
130 | unsigned int last_mii_status; | ||
131 | struct fs_enet_mii_bus *mii_bus; | ||
132 | int interrupt; | ||
133 | |||
134 | int duplex, speed; /* current settings */ | ||
135 | |||
136 | /* event masks */ | ||
137 | u32 ev_napi_rx; /* mask of NAPI rx events */ | ||
138 | u32 ev_rx; /* rx event mask */ | ||
139 | u32 ev_tx; /* tx event mask */ | ||
140 | u32 ev_err; /* error event mask */ | ||
141 | |||
142 | u16 bd_rx_empty; /* mask of BD rx empty */ | ||
143 | u16 bd_rx_err; /* mask of BD rx errors */ | ||
144 | |||
145 | union { | ||
146 | struct { | ||
147 | int idx; /* FEC1 = 0, FEC2 = 1 */ | ||
148 | void *fecp; /* hw registers */ | ||
149 | u32 hthi, htlo; /* state for multicast */ | ||
150 | } fec; | ||
151 | |||
152 | struct { | ||
153 | int idx; /* FCC1-3 = 0-2 */ | ||
154 | void *fccp; /* hw registers */ | ||
155 | void *ep; /* parameter ram */ | ||
156 | void *fcccp; /* hw registers cont. */ | ||
157 | void *mem; /* FCC DPRAM */ | ||
158 | u32 gaddrh, gaddrl; /* group address */ | ||
159 | } fcc; | ||
160 | |||
161 | struct { | ||
162 | int idx; /* FEC1 = 0, FEC2 = 1 */ | ||
163 | void *sccp; /* hw registers */ | ||
164 | void *ep; /* parameter ram */ | ||
165 | u32 hthi, htlo; /* state for multicast */ | ||
166 | } scc; | ||
167 | |||
168 | }; | ||
169 | }; | ||
170 | |||
171 | /***************************************************************************/ | ||
172 | |||
173 | int fs_mii_read(struct net_device *dev, int phy_id, int location); | ||
174 | void fs_mii_write(struct net_device *dev, int phy_id, int location, int value); | ||
175 | |||
176 | void fs_mii_startup(struct net_device *dev); | ||
177 | void fs_mii_shutdown(struct net_device *dev); | ||
178 | void fs_mii_ack_int(struct net_device *dev); | ||
179 | |||
180 | void fs_mii_link_status_change_check(struct net_device *dev, int init_media); | ||
181 | |||
182 | void fs_init_bds(struct net_device *dev); | ||
183 | void fs_cleanup_bds(struct net_device *dev); | ||
184 | |||
185 | /***************************************************************************/ | ||
186 | |||
187 | #define DRV_MODULE_NAME "fs_enet" | ||
188 | #define PFX DRV_MODULE_NAME ": " | ||
189 | #define DRV_MODULE_VERSION "1.0" | ||
190 | #define DRV_MODULE_RELDATE "Aug 8, 2005" | ||
191 | |||
192 | /***************************************************************************/ | ||
193 | |||
194 | int fs_enet_platform_init(void); | ||
195 | void fs_enet_platform_cleanup(void); | ||
196 | |||
197 | /***************************************************************************/ | ||
198 | |||
199 | /* buffer descriptor access macros */ | ||
200 | |||
201 | /* access macros */ | ||
202 | #if defined(CONFIG_CPM1) | ||
203 | /* for a a CPM1 __raw_xxx's are sufficient */ | ||
204 | #define __cbd_out32(addr, x) __raw_writel(x, addr) | ||
205 | #define __cbd_out16(addr, x) __raw_writew(x, addr) | ||
206 | #define __cbd_in32(addr) __raw_readl(addr) | ||
207 | #define __cbd_in16(addr) __raw_readw(addr) | ||
208 | #else | ||
209 | /* for others play it safe */ | ||
210 | #define __cbd_out32(addr, x) out_be32(addr, x) | ||
211 | #define __cbd_out16(addr, x) out_be16(addr, x) | ||
212 | #define __cbd_in32(addr) in_be32(addr) | ||
213 | #define __cbd_in16(addr) in_be16(addr) | ||
214 | #endif | ||
215 | |||
216 | /* write */ | ||
217 | #define CBDW_SC(_cbd, _sc) __cbd_out16(&(_cbd)->cbd_sc, (_sc)) | ||
218 | #define CBDW_DATLEN(_cbd, _datlen) __cbd_out16(&(_cbd)->cbd_datlen, (_datlen)) | ||
219 | #define CBDW_BUFADDR(_cbd, _bufaddr) __cbd_out32(&(_cbd)->cbd_bufaddr, (_bufaddr)) | ||
220 | |||
221 | /* read */ | ||
222 | #define CBDR_SC(_cbd) __cbd_in16(&(_cbd)->cbd_sc) | ||
223 | #define CBDR_DATLEN(_cbd) __cbd_in16(&(_cbd)->cbd_datlen) | ||
224 | #define CBDR_BUFADDR(_cbd) __cbd_in32(&(_cbd)->cbd_bufaddr) | ||
225 | |||
226 | /* set bits */ | ||
227 | #define CBDS_SC(_cbd, _sc) CBDW_SC(_cbd, CBDR_SC(_cbd) | (_sc)) | ||
228 | |||
229 | /* clear bits */ | ||
230 | #define CBDC_SC(_cbd, _sc) CBDW_SC(_cbd, CBDR_SC(_cbd) & ~(_sc)) | ||
231 | |||
232 | /*******************************************************************/ | ||
233 | |||
234 | extern const struct fs_ops fs_fec_ops; | ||
235 | extern const struct fs_ops fs_fcc_ops; | ||
236 | extern const struct fs_ops fs_scc_ops; | ||
237 | |||
238 | /*******************************************************************/ | ||
239 | |||
240 | /* handy pointer to the immap */ | ||
241 | extern void *fs_enet_immap; | ||
242 | |||
243 | /*******************************************************************/ | ||
244 | |||
245 | #endif | ||
diff --git a/drivers/net/fs_enet/mac-fcc.c b/drivers/net/fs_enet/mac-fcc.c new file mode 100644 index 000000000000..a940b96433c7 --- /dev/null +++ b/drivers/net/fs_enet/mac-fcc.c | |||
@@ -0,0 +1,578 @@ | |||
1 | /* | ||
2 | * FCC driver for Motorola MPC82xx (PQ2). | ||
3 | * | ||
4 | * Copyright (c) 2003 Intracom S.A. | ||
5 | * by Pantelis Antoniou <panto@intracom.gr> | ||
6 | * | ||
7 | * 2005 (c) MontaVista Software, Inc. | ||
8 | * Vitaly Bordug <vbordug@ru.mvista.com> | ||
9 | * | ||
10 | * This file is licensed under the terms of the GNU General Public License | ||
11 | * version 2. This program is licensed "as is" without any warranty of any | ||
12 | * kind, whether express or implied. | ||
13 | */ | ||
14 | |||
15 | #include <linux/config.h> | ||
16 | #include <linux/module.h> | ||
17 | #include <linux/kernel.h> | ||
18 | #include <linux/types.h> | ||
19 | #include <linux/sched.h> | ||
20 | #include <linux/string.h> | ||
21 | #include <linux/ptrace.h> | ||
22 | #include <linux/errno.h> | ||
23 | #include <linux/ioport.h> | ||
24 | #include <linux/slab.h> | ||
25 | #include <linux/interrupt.h> | ||
26 | #include <linux/pci.h> | ||
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> | ||
37 | |||
38 | #include <asm/immap_cpm2.h> | ||
39 | #include <asm/mpc8260.h> | ||
40 | #include <asm/cpm2.h> | ||
41 | |||
42 | #include <asm/pgtable.h> | ||
43 | #include <asm/irq.h> | ||
44 | #include <asm/uaccess.h> | ||
45 | |||
46 | #include "fs_enet.h" | ||
47 | |||
48 | /*************************************************/ | ||
49 | |||
50 | /* FCC access macros */ | ||
51 | |||
52 | #define __fcc_out32(addr, x) out_be32((unsigned *)addr, x) | ||
53 | #define __fcc_out16(addr, x) out_be16((unsigned short *)addr, x) | ||
54 | #define __fcc_out8(addr, x) out_8((unsigned char *)addr, x) | ||
55 | #define __fcc_in32(addr) in_be32((unsigned *)addr) | ||
56 | #define __fcc_in16(addr) in_be16((unsigned short *)addr) | ||
57 | #define __fcc_in8(addr) in_8((unsigned char *)addr) | ||
58 | |||
59 | /* parameter space */ | ||
60 | |||
61 | /* write, read, set bits, clear bits */ | ||
62 | #define W32(_p, _m, _v) __fcc_out32(&(_p)->_m, (_v)) | ||
63 | #define R32(_p, _m) __fcc_in32(&(_p)->_m) | ||
64 | #define S32(_p, _m, _v) W32(_p, _m, R32(_p, _m) | (_v)) | ||
65 | #define C32(_p, _m, _v) W32(_p, _m, R32(_p, _m) & ~(_v)) | ||
66 | |||
67 | #define W16(_p, _m, _v) __fcc_out16(&(_p)->_m, (_v)) | ||
68 | #define R16(_p, _m) __fcc_in16(&(_p)->_m) | ||
69 | #define S16(_p, _m, _v) W16(_p, _m, R16(_p, _m) | (_v)) | ||
70 | #define C16(_p, _m, _v) W16(_p, _m, R16(_p, _m) & ~(_v)) | ||
71 | |||
72 | #define W8(_p, _m, _v) __fcc_out8(&(_p)->_m, (_v)) | ||
73 | #define R8(_p, _m) __fcc_in8(&(_p)->_m) | ||
74 | #define S8(_p, _m, _v) W8(_p, _m, R8(_p, _m) | (_v)) | ||
75 | #define C8(_p, _m, _v) W8(_p, _m, R8(_p, _m) & ~(_v)) | ||
76 | |||
77 | /*************************************************/ | ||
78 | |||
79 | #define FCC_MAX_MULTICAST_ADDRS 64 | ||
80 | |||
81 | #define mk_mii_read(REG) (0x60020000 | ((REG & 0x1f) << 18)) | ||
82 | #define mk_mii_write(REG, VAL) (0x50020000 | ((REG & 0x1f) << 18) | (VAL & 0xffff)) | ||
83 | #define mk_mii_end 0 | ||
84 | |||
85 | #define MAX_CR_CMD_LOOPS 10000 | ||
86 | |||
87 | static inline int fcc_cr_cmd(struct fs_enet_private *fep, u32 mcn, u32 op) | ||
88 | { | ||
89 | const struct fs_platform_info *fpi = fep->fpi; | ||
90 | |||
91 | cpm2_map_t *immap = fs_enet_immap; | ||
92 | cpm_cpm2_t *cpmp = &immap->im_cpm; | ||
93 | u32 v; | ||
94 | int i; | ||
95 | |||
96 | /* Currently I don't know what feature call will look like. But | ||
97 | I guess there'd be something like do_cpm_cmd() which will require page & sblock */ | ||
98 | v = mk_cr_cmd(fpi->cp_page, fpi->cp_block, mcn, op); | ||
99 | W32(cpmp, cp_cpcr, v | CPM_CR_FLG); | ||
100 | for (i = 0; i < MAX_CR_CMD_LOOPS; i++) | ||
101 | if ((R32(cpmp, cp_cpcr) & CPM_CR_FLG) == 0) | ||
102 | break; | ||
103 | |||
104 | if (i >= MAX_CR_CMD_LOOPS) { | ||
105 | printk(KERN_ERR "%s(): Not able to issue CPM command\n", | ||
106 | __FUNCTION__); | ||
107 | return 1; | ||
108 | } | ||
109 | |||
110 | return 0; | ||
111 | } | ||
112 | |||
113 | static int do_pd_setup(struct fs_enet_private *fep) | ||
114 | { | ||
115 | struct platform_device *pdev = to_platform_device(fep->dev); | ||
116 | struct resource *r; | ||
117 | |||
118 | /* Fill out IRQ field */ | ||
119 | fep->interrupt = platform_get_irq(pdev, 0); | ||
120 | |||
121 | /* Attach the memory for the FCC Parameter RAM */ | ||
122 | r = platform_get_resource_byname(pdev, IORESOURCE_MEM, "fcc_pram"); | ||
123 | fep->fcc.ep = (void *)r->start; | ||
124 | |||
125 | if (fep->fcc.ep == NULL) | ||
126 | return -EINVAL; | ||
127 | |||
128 | r = platform_get_resource_byname(pdev, IORESOURCE_MEM, "fcc_regs"); | ||
129 | fep->fcc.fccp = (void *)r->start; | ||
130 | |||
131 | if (fep->fcc.fccp == NULL) | ||
132 | return -EINVAL; | ||
133 | |||
134 | fep->fcc.fcccp = (void *)fep->fpi->fcc_regs_c; | ||
135 | |||
136 | if (fep->fcc.fcccp == NULL) | ||
137 | return -EINVAL; | ||
138 | |||
139 | return 0; | ||
140 | } | ||
141 | |||
142 | #define FCC_NAPI_RX_EVENT_MSK (FCC_ENET_RXF | FCC_ENET_RXB) | ||
143 | #define FCC_RX_EVENT (FCC_ENET_RXF) | ||
144 | #define FCC_TX_EVENT (FCC_ENET_TXB) | ||
145 | #define FCC_ERR_EVENT_MSK (FCC_ENET_TXE | FCC_ENET_BSY) | ||
146 | |||
147 | static int setup_data(struct net_device *dev) | ||
148 | { | ||
149 | struct fs_enet_private *fep = netdev_priv(dev); | ||
150 | const struct fs_platform_info *fpi = fep->fpi; | ||
151 | |||
152 | fep->fcc.idx = fs_get_fcc_index(fpi->fs_no); | ||
153 | if ((unsigned int)fep->fcc.idx >= 3) /* max 3 FCCs */ | ||
154 | return -EINVAL; | ||
155 | |||
156 | fep->fcc.mem = (void *)fpi->mem_offset; | ||
157 | |||
158 | if (do_pd_setup(fep) != 0) | ||
159 | return -EINVAL; | ||
160 | |||
161 | fep->ev_napi_rx = FCC_NAPI_RX_EVENT_MSK; | ||
162 | fep->ev_rx = FCC_RX_EVENT; | ||
163 | fep->ev_tx = FCC_TX_EVENT; | ||
164 | fep->ev_err = FCC_ERR_EVENT_MSK; | ||
165 | |||
166 | return 0; | ||
167 | } | ||
168 | |||
169 | static int allocate_bd(struct net_device *dev) | ||
170 | { | ||
171 | struct fs_enet_private *fep = netdev_priv(dev); | ||
172 | const struct fs_platform_info *fpi = fep->fpi; | ||
173 | |||
174 | fep->ring_base = dma_alloc_coherent(fep->dev, | ||
175 | (fpi->tx_ring + fpi->rx_ring) * | ||
176 | sizeof(cbd_t), &fep->ring_mem_addr, | ||
177 | GFP_KERNEL); | ||
178 | if (fep->ring_base == NULL) | ||
179 | return -ENOMEM; | ||
180 | |||
181 | return 0; | ||
182 | } | ||
183 | |||
184 | static void free_bd(struct net_device *dev) | ||
185 | { | ||
186 | struct fs_enet_private *fep = netdev_priv(dev); | ||
187 | const struct fs_platform_info *fpi = fep->fpi; | ||
188 | |||
189 | if (fep->ring_base) | ||
190 | dma_free_coherent(fep->dev, | ||
191 | (fpi->tx_ring + fpi->rx_ring) * sizeof(cbd_t), | ||
192 | fep->ring_base, fep->ring_mem_addr); | ||
193 | } | ||
194 | |||
195 | static void cleanup_data(struct net_device *dev) | ||
196 | { | ||
197 | /* nothing */ | ||
198 | } | ||
199 | |||
200 | static void set_promiscuous_mode(struct net_device *dev) | ||
201 | { | ||
202 | struct fs_enet_private *fep = netdev_priv(dev); | ||
203 | fcc_t *fccp = fep->fcc.fccp; | ||
204 | |||
205 | S32(fccp, fcc_fpsmr, FCC_PSMR_PRO); | ||
206 | } | ||
207 | |||
208 | static void set_multicast_start(struct net_device *dev) | ||
209 | { | ||
210 | struct fs_enet_private *fep = netdev_priv(dev); | ||
211 | fcc_enet_t *ep = fep->fcc.ep; | ||
212 | |||
213 | W32(ep, fen_gaddrh, 0); | ||
214 | W32(ep, fen_gaddrl, 0); | ||
215 | } | ||
216 | |||
217 | static void set_multicast_one(struct net_device *dev, const u8 *mac) | ||
218 | { | ||
219 | struct fs_enet_private *fep = netdev_priv(dev); | ||
220 | fcc_enet_t *ep = fep->fcc.ep; | ||
221 | u16 taddrh, taddrm, taddrl; | ||
222 | |||
223 | taddrh = ((u16)mac[5] << 8) | mac[4]; | ||
224 | taddrm = ((u16)mac[3] << 8) | mac[2]; | ||
225 | taddrl = ((u16)mac[1] << 8) | mac[0]; | ||
226 | |||
227 | W16(ep, fen_taddrh, taddrh); | ||
228 | W16(ep, fen_taddrm, taddrm); | ||
229 | W16(ep, fen_taddrl, taddrl); | ||
230 | fcc_cr_cmd(fep, 0x0C, CPM_CR_SET_GADDR); | ||
231 | } | ||
232 | |||
233 | static void set_multicast_finish(struct net_device *dev) | ||
234 | { | ||
235 | struct fs_enet_private *fep = netdev_priv(dev); | ||
236 | fcc_t *fccp = fep->fcc.fccp; | ||
237 | fcc_enet_t *ep = fep->fcc.ep; | ||
238 | |||
239 | /* clear promiscuous always */ | ||
240 | C32(fccp, fcc_fpsmr, FCC_PSMR_PRO); | ||
241 | |||
242 | /* if all multi or too many multicasts; just enable all */ | ||
243 | if ((dev->flags & IFF_ALLMULTI) != 0 || | ||
244 | dev->mc_count > FCC_MAX_MULTICAST_ADDRS) { | ||
245 | |||
246 | W32(ep, fen_gaddrh, 0xffffffff); | ||
247 | W32(ep, fen_gaddrl, 0xffffffff); | ||
248 | } | ||
249 | |||
250 | /* read back */ | ||
251 | fep->fcc.gaddrh = R32(ep, fen_gaddrh); | ||
252 | fep->fcc.gaddrl = R32(ep, fen_gaddrl); | ||
253 | } | ||
254 | |||
255 | static void set_multicast_list(struct net_device *dev) | ||
256 | { | ||
257 | struct dev_mc_list *pmc; | ||
258 | |||
259 | if ((dev->flags & IFF_PROMISC) == 0) { | ||
260 | set_multicast_start(dev); | ||
261 | for (pmc = dev->mc_list; pmc != NULL; pmc = pmc->next) | ||
262 | set_multicast_one(dev, pmc->dmi_addr); | ||
263 | set_multicast_finish(dev); | ||
264 | } else | ||
265 | set_promiscuous_mode(dev); | ||
266 | } | ||
267 | |||
268 | static void restart(struct net_device *dev) | ||
269 | { | ||
270 | struct fs_enet_private *fep = netdev_priv(dev); | ||
271 | const struct fs_platform_info *fpi = fep->fpi; | ||
272 | fcc_t *fccp = fep->fcc.fccp; | ||
273 | fcc_c_t *fcccp = fep->fcc.fcccp; | ||
274 | fcc_enet_t *ep = fep->fcc.ep; | ||
275 | dma_addr_t rx_bd_base_phys, tx_bd_base_phys; | ||
276 | u16 paddrh, paddrm, paddrl; | ||
277 | u16 mem_addr; | ||
278 | const unsigned char *mac; | ||
279 | int i; | ||
280 | |||
281 | C32(fccp, fcc_gfmr, FCC_GFMR_ENR | FCC_GFMR_ENT); | ||
282 | |||
283 | /* clear everything (slow & steady does it) */ | ||
284 | for (i = 0; i < sizeof(*ep); i++) | ||
285 | __fcc_out8((char *)ep + i, 0); | ||
286 | |||
287 | /* get physical address */ | ||
288 | rx_bd_base_phys = fep->ring_mem_addr; | ||
289 | tx_bd_base_phys = rx_bd_base_phys + sizeof(cbd_t) * fpi->rx_ring; | ||
290 | |||
291 | /* point to bds */ | ||
292 | W32(ep, fen_genfcc.fcc_rbase, rx_bd_base_phys); | ||
293 | W32(ep, fen_genfcc.fcc_tbase, tx_bd_base_phys); | ||
294 | |||
295 | /* Set maximum bytes per receive buffer. | ||
296 | * It must be a multiple of 32. | ||
297 | */ | ||
298 | W16(ep, fen_genfcc.fcc_mrblr, PKT_MAXBLR_SIZE); | ||
299 | |||
300 | W32(ep, fen_genfcc.fcc_rstate, (CPMFCR_GBL | CPMFCR_EB) << 24); | ||
301 | W32(ep, fen_genfcc.fcc_tstate, (CPMFCR_GBL | CPMFCR_EB) << 24); | ||
302 | |||
303 | /* Allocate space in the reserved FCC area of DPRAM for the | ||
304 | * internal buffers. No one uses this space (yet), so we | ||
305 | * can do this. Later, we will add resource management for | ||
306 | * this area. | ||
307 | */ | ||
308 | |||
309 | mem_addr = (u32) fep->fcc.mem; /* de-fixup dpram offset */ | ||
310 | |||
311 | W16(ep, fen_genfcc.fcc_riptr, (mem_addr & 0xffff)); | ||
312 | W16(ep, fen_genfcc.fcc_tiptr, ((mem_addr + 32) & 0xffff)); | ||
313 | W16(ep, fen_padptr, mem_addr + 64); | ||
314 | |||
315 | /* fill with special symbol... */ | ||
316 | memset(fep->fcc.mem + fpi->dpram_offset + 64, 0x88, 32); | ||
317 | |||
318 | W32(ep, fen_genfcc.fcc_rbptr, 0); | ||
319 | W32(ep, fen_genfcc.fcc_tbptr, 0); | ||
320 | W32(ep, fen_genfcc.fcc_rcrc, 0); | ||
321 | W32(ep, fen_genfcc.fcc_tcrc, 0); | ||
322 | W16(ep, fen_genfcc.fcc_res1, 0); | ||
323 | W32(ep, fen_genfcc.fcc_res2, 0); | ||
324 | |||
325 | /* no CAM */ | ||
326 | W32(ep, fen_camptr, 0); | ||
327 | |||
328 | /* Set CRC preset and mask */ | ||
329 | W32(ep, fen_cmask, 0xdebb20e3); | ||
330 | W32(ep, fen_cpres, 0xffffffff); | ||
331 | |||
332 | W32(ep, fen_crcec, 0); /* CRC Error counter */ | ||
333 | W32(ep, fen_alec, 0); /* alignment error counter */ | ||
334 | W32(ep, fen_disfc, 0); /* discard frame counter */ | ||
335 | W16(ep, fen_retlim, 15); /* Retry limit threshold */ | ||
336 | W16(ep, fen_pper, 0); /* Normal persistence */ | ||
337 | |||
338 | /* set group address */ | ||
339 | W32(ep, fen_gaddrh, fep->fcc.gaddrh); | ||
340 | W32(ep, fen_gaddrl, fep->fcc.gaddrh); | ||
341 | |||
342 | /* Clear hash filter tables */ | ||
343 | W32(ep, fen_iaddrh, 0); | ||
344 | W32(ep, fen_iaddrl, 0); | ||
345 | |||
346 | /* Clear the Out-of-sequence TxBD */ | ||
347 | W16(ep, fen_tfcstat, 0); | ||
348 | W16(ep, fen_tfclen, 0); | ||
349 | W32(ep, fen_tfcptr, 0); | ||
350 | |||
351 | W16(ep, fen_mflr, PKT_MAXBUF_SIZE); /* maximum frame length register */ | ||
352 | W16(ep, fen_minflr, PKT_MINBUF_SIZE); /* minimum frame length register */ | ||
353 | |||
354 | /* set address */ | ||
355 | mac = dev->dev_addr; | ||
356 | paddrh = ((u16)mac[5] << 8) | mac[4]; | ||
357 | paddrm = ((u16)mac[3] << 8) | mac[2]; | ||
358 | paddrl = ((u16)mac[1] << 8) | mac[0]; | ||
359 | |||
360 | W16(ep, fen_paddrh, paddrh); | ||
361 | W16(ep, fen_paddrm, paddrm); | ||
362 | W16(ep, fen_paddrl, paddrl); | ||
363 | |||
364 | W16(ep, fen_taddrh, 0); | ||
365 | W16(ep, fen_taddrm, 0); | ||
366 | W16(ep, fen_taddrl, 0); | ||
367 | |||
368 | W16(ep, fen_maxd1, 1520); /* maximum DMA1 length */ | ||
369 | W16(ep, fen_maxd2, 1520); /* maximum DMA2 length */ | ||
370 | |||
371 | /* Clear stat counters, in case we ever enable RMON */ | ||
372 | W32(ep, fen_octc, 0); | ||
373 | W32(ep, fen_colc, 0); | ||
374 | W32(ep, fen_broc, 0); | ||
375 | W32(ep, fen_mulc, 0); | ||
376 | W32(ep, fen_uspc, 0); | ||
377 | W32(ep, fen_frgc, 0); | ||
378 | W32(ep, fen_ospc, 0); | ||
379 | W32(ep, fen_jbrc, 0); | ||
380 | W32(ep, fen_p64c, 0); | ||
381 | W32(ep, fen_p65c, 0); | ||
382 | W32(ep, fen_p128c, 0); | ||
383 | W32(ep, fen_p256c, 0); | ||
384 | W32(ep, fen_p512c, 0); | ||
385 | W32(ep, fen_p1024c, 0); | ||
386 | |||
387 | W16(ep, fen_rfthr, 0); /* Suggested by manual */ | ||
388 | W16(ep, fen_rfcnt, 0); | ||
389 | W16(ep, fen_cftype, 0); | ||
390 | |||
391 | fs_init_bds(dev); | ||
392 | |||
393 | /* adjust to speed (for RMII mode) */ | ||
394 | if (fpi->use_rmii) { | ||
395 | if (fep->speed == 100) | ||
396 | C8(fcccp, fcc_gfemr, 0x20); | ||
397 | else | ||
398 | S8(fcccp, fcc_gfemr, 0x20); | ||
399 | } | ||
400 | |||
401 | fcc_cr_cmd(fep, 0x0c, CPM_CR_INIT_TRX); | ||
402 | |||
403 | /* clear events */ | ||
404 | W16(fccp, fcc_fcce, 0xffff); | ||
405 | |||
406 | /* Enable interrupts we wish to service */ | ||
407 | W16(fccp, fcc_fccm, FCC_ENET_TXE | FCC_ENET_RXF | FCC_ENET_TXB); | ||
408 | |||
409 | /* Set GFMR to enable Ethernet operating mode */ | ||
410 | W32(fccp, fcc_gfmr, FCC_GFMR_TCI | FCC_GFMR_MODE_ENET); | ||
411 | |||
412 | /* set sync/delimiters */ | ||
413 | W16(fccp, fcc_fdsr, 0xd555); | ||
414 | |||
415 | W32(fccp, fcc_fpsmr, FCC_PSMR_ENCRC); | ||
416 | |||
417 | if (fpi->use_rmii) | ||
418 | S32(fccp, fcc_fpsmr, FCC_PSMR_RMII); | ||
419 | |||
420 | /* adjust to duplex mode */ | ||
421 | if (fep->duplex) | ||
422 | S32(fccp, fcc_fpsmr, FCC_PSMR_FDE | FCC_PSMR_LPB); | ||
423 | else | ||
424 | C32(fccp, fcc_fpsmr, FCC_PSMR_FDE | FCC_PSMR_LPB); | ||
425 | |||
426 | S32(fccp, fcc_gfmr, FCC_GFMR_ENR | FCC_GFMR_ENT); | ||
427 | } | ||
428 | |||
429 | static void stop(struct net_device *dev) | ||
430 | { | ||
431 | struct fs_enet_private *fep = netdev_priv(dev); | ||
432 | fcc_t *fccp = fep->fcc.fccp; | ||
433 | |||
434 | /* stop ethernet */ | ||
435 | C32(fccp, fcc_gfmr, FCC_GFMR_ENR | FCC_GFMR_ENT); | ||
436 | |||
437 | /* clear events */ | ||
438 | W16(fccp, fcc_fcce, 0xffff); | ||
439 | |||
440 | /* clear interrupt mask */ | ||
441 | W16(fccp, fcc_fccm, 0); | ||
442 | |||
443 | fs_cleanup_bds(dev); | ||
444 | } | ||
445 | |||
446 | static void pre_request_irq(struct net_device *dev, int irq) | ||
447 | { | ||
448 | /* nothing */ | ||
449 | } | ||
450 | |||
451 | static void post_free_irq(struct net_device *dev, int irq) | ||
452 | { | ||
453 | /* nothing */ | ||
454 | } | ||
455 | |||
456 | static void napi_clear_rx_event(struct net_device *dev) | ||
457 | { | ||
458 | struct fs_enet_private *fep = netdev_priv(dev); | ||
459 | fcc_t *fccp = fep->fcc.fccp; | ||
460 | |||
461 | W16(fccp, fcc_fcce, FCC_NAPI_RX_EVENT_MSK); | ||
462 | } | ||
463 | |||
464 | static void napi_enable_rx(struct net_device *dev) | ||
465 | { | ||
466 | struct fs_enet_private *fep = netdev_priv(dev); | ||
467 | fcc_t *fccp = fep->fcc.fccp; | ||
468 | |||
469 | S16(fccp, fcc_fccm, FCC_NAPI_RX_EVENT_MSK); | ||
470 | } | ||
471 | |||
472 | static void napi_disable_rx(struct net_device *dev) | ||
473 | { | ||
474 | struct fs_enet_private *fep = netdev_priv(dev); | ||
475 | fcc_t *fccp = fep->fcc.fccp; | ||
476 | |||
477 | C16(fccp, fcc_fccm, FCC_NAPI_RX_EVENT_MSK); | ||
478 | } | ||
479 | |||
480 | static void rx_bd_done(struct net_device *dev) | ||
481 | { | ||
482 | /* nothing */ | ||
483 | } | ||
484 | |||
485 | static void tx_kickstart(struct net_device *dev) | ||
486 | { | ||
487 | /* nothing */ | ||
488 | } | ||
489 | |||
490 | static u32 get_int_events(struct net_device *dev) | ||
491 | { | ||
492 | struct fs_enet_private *fep = netdev_priv(dev); | ||
493 | fcc_t *fccp = fep->fcc.fccp; | ||
494 | |||
495 | return (u32)R16(fccp, fcc_fcce); | ||
496 | } | ||
497 | |||
498 | static void clear_int_events(struct net_device *dev, u32 int_events) | ||
499 | { | ||
500 | struct fs_enet_private *fep = netdev_priv(dev); | ||
501 | fcc_t *fccp = fep->fcc.fccp; | ||
502 | |||
503 | W16(fccp, fcc_fcce, int_events & 0xffff); | ||
504 | } | ||
505 | |||
506 | static void ev_error(struct net_device *dev, u32 int_events) | ||
507 | { | ||
508 | printk(KERN_WARNING DRV_MODULE_NAME | ||
509 | ": %s FS_ENET ERROR(s) 0x%x\n", dev->name, int_events); | ||
510 | } | ||
511 | |||
512 | int get_regs(struct net_device *dev, void *p, int *sizep) | ||
513 | { | ||
514 | struct fs_enet_private *fep = netdev_priv(dev); | ||
515 | |||
516 | if (*sizep < sizeof(fcc_t) + sizeof(fcc_c_t) + sizeof(fcc_enet_t)) | ||
517 | return -EINVAL; | ||
518 | |||
519 | memcpy_fromio(p, fep->fcc.fccp, sizeof(fcc_t)); | ||
520 | p = (char *)p + sizeof(fcc_t); | ||
521 | |||
522 | memcpy_fromio(p, fep->fcc.fcccp, sizeof(fcc_c_t)); | ||
523 | p = (char *)p + sizeof(fcc_c_t); | ||
524 | |||
525 | memcpy_fromio(p, fep->fcc.ep, sizeof(fcc_enet_t)); | ||
526 | |||
527 | return 0; | ||
528 | } | ||
529 | |||
530 | int get_regs_len(struct net_device *dev) | ||
531 | { | ||
532 | return sizeof(fcc_t) + sizeof(fcc_c_t) + sizeof(fcc_enet_t); | ||
533 | } | ||
534 | |||
535 | /* Some transmit errors cause the transmitter to shut | ||
536 | * down. We now issue a restart transmit. Since the | ||
537 | * errors close the BD and update the pointers, the restart | ||
538 | * _should_ pick up without having to reset any of our | ||
539 | * pointers either. Also, To workaround 8260 device erratum | ||
540 | * CPM37, we must disable and then re-enable the transmitter | ||
541 | * following a Late Collision, Underrun, or Retry Limit error. | ||
542 | */ | ||
543 | void tx_restart(struct net_device *dev) | ||
544 | { | ||
545 | struct fs_enet_private *fep = netdev_priv(dev); | ||
546 | fcc_t *fccp = fep->fcc.fccp; | ||
547 | |||
548 | C32(fccp, fcc_gfmr, FCC_GFMR_ENT); | ||
549 | udelay(10); | ||
550 | S32(fccp, fcc_gfmr, FCC_GFMR_ENT); | ||
551 | |||
552 | fcc_cr_cmd(fep, 0x0C, CPM_CR_RESTART_TX); | ||
553 | } | ||
554 | |||
555 | /*************************************************************************/ | ||
556 | |||
557 | const struct fs_ops fs_fcc_ops = { | ||
558 | .setup_data = setup_data, | ||
559 | .cleanup_data = cleanup_data, | ||
560 | .set_multicast_list = set_multicast_list, | ||
561 | .restart = restart, | ||
562 | .stop = stop, | ||
563 | .pre_request_irq = pre_request_irq, | ||
564 | .post_free_irq = post_free_irq, | ||
565 | .napi_clear_rx_event = napi_clear_rx_event, | ||
566 | .napi_enable_rx = napi_enable_rx, | ||
567 | .napi_disable_rx = napi_disable_rx, | ||
568 | .rx_bd_done = rx_bd_done, | ||
569 | .tx_kickstart = tx_kickstart, | ||
570 | .get_int_events = get_int_events, | ||
571 | .clear_int_events = clear_int_events, | ||
572 | .ev_error = ev_error, | ||
573 | .get_regs = get_regs, | ||
574 | .get_regs_len = get_regs_len, | ||
575 | .tx_restart = tx_restart, | ||
576 | .allocate_bd = allocate_bd, | ||
577 | .free_bd = free_bd, | ||
578 | }; | ||
diff --git a/drivers/net/fs_enet/mac-fec.c b/drivers/net/fs_enet/mac-fec.c new file mode 100644 index 000000000000..5ef4e845a387 --- /dev/null +++ b/drivers/net/fs_enet/mac-fec.c | |||
@@ -0,0 +1,653 @@ | |||
1 | /* | ||
2 | * Freescale Ethernet controllers | ||
3 | * | ||
4 | * Copyright (c) 2005 Intracom S.A. | ||
5 | * by Pantelis Antoniou <panto@intracom.gr> | ||
6 | * | ||
7 | * 2005 (c) MontaVista Software, Inc. | ||
8 | * Vitaly Bordug <vbordug@ru.mvista.com> | ||
9 | * | ||
10 | * This file is licensed under the terms of the GNU General Public License | ||
11 | * version 2. This program is licensed "as is" without any warranty of any | ||
12 | * kind, whether express or implied. | ||
13 | */ | ||
14 | |||
15 | #include <linux/config.h> | ||
16 | #include <linux/module.h> | ||
17 | #include <linux/kernel.h> | ||
18 | #include <linux/types.h> | ||
19 | #include <linux/sched.h> | ||
20 | #include <linux/string.h> | ||
21 | #include <linux/ptrace.h> | ||
22 | #include <linux/errno.h> | ||
23 | #include <linux/ioport.h> | ||
24 | #include <linux/slab.h> | ||
25 | #include <linux/interrupt.h> | ||
26 | #include <linux/pci.h> | ||
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> | ||
37 | |||
38 | #include <asm/irq.h> | ||
39 | #include <asm/uaccess.h> | ||
40 | |||
41 | #ifdef CONFIG_8xx | ||
42 | #include <asm/8xx_immap.h> | ||
43 | #include <asm/pgtable.h> | ||
44 | #include <asm/mpc8xx.h> | ||
45 | #include <asm/commproc.h> | ||
46 | #endif | ||
47 | |||
48 | #include "fs_enet.h" | ||
49 | |||
50 | /*************************************************/ | ||
51 | |||
52 | #if defined(CONFIG_CPM1) | ||
53 | /* for a CPM1 __raw_xxx's are sufficient */ | ||
54 | #define __fs_out32(addr, x) __raw_writel(x, addr) | ||
55 | #define __fs_out16(addr, x) __raw_writew(x, addr) | ||
56 | #define __fs_in32(addr) __raw_readl(addr) | ||
57 | #define __fs_in16(addr) __raw_readw(addr) | ||
58 | #else | ||
59 | /* for others play it safe */ | ||
60 | #define __fs_out32(addr, x) out_be32(addr, x) | ||
61 | #define __fs_out16(addr, x) out_be16(addr, x) | ||
62 | #define __fs_in32(addr) in_be32(addr) | ||
63 | #define __fs_in16(addr) in_be16(addr) | ||
64 | #endif | ||
65 | |||
66 | /* write */ | ||
67 | #define FW(_fecp, _reg, _v) __fs_out32(&(_fecp)->fec_ ## _reg, (_v)) | ||
68 | |||
69 | /* read */ | ||
70 | #define FR(_fecp, _reg) __fs_in32(&(_fecp)->fec_ ## _reg) | ||
71 | |||
72 | /* set bits */ | ||
73 | #define FS(_fecp, _reg, _v) FW(_fecp, _reg, FR(_fecp, _reg) | (_v)) | ||
74 | |||
75 | /* clear bits */ | ||
76 | #define FC(_fecp, _reg, _v) FW(_fecp, _reg, FR(_fecp, _reg) & ~(_v)) | ||
77 | |||
78 | |||
79 | /* CRC polynomium used by the FEC for the multicast group filtering */ | ||
80 | #define FEC_CRC_POLY 0x04C11DB7 | ||
81 | |||
82 | #define FEC_MAX_MULTICAST_ADDRS 64 | ||
83 | |||
84 | /* Interrupt events/masks. | ||
85 | */ | ||
86 | #define FEC_ENET_HBERR 0x80000000U /* Heartbeat error */ | ||
87 | #define FEC_ENET_BABR 0x40000000U /* Babbling receiver */ | ||
88 | #define FEC_ENET_BABT 0x20000000U /* Babbling transmitter */ | ||
89 | #define FEC_ENET_GRA 0x10000000U /* Graceful stop complete */ | ||
90 | #define FEC_ENET_TXF 0x08000000U /* Full frame transmitted */ | ||
91 | #define FEC_ENET_TXB 0x04000000U /* A buffer was transmitted */ | ||
92 | #define FEC_ENET_RXF 0x02000000U /* Full frame received */ | ||
93 | #define FEC_ENET_RXB 0x01000000U /* A buffer was received */ | ||
94 | #define FEC_ENET_MII 0x00800000U /* MII interrupt */ | ||
95 | #define FEC_ENET_EBERR 0x00400000U /* SDMA bus error */ | ||
96 | |||
97 | #define FEC_ECNTRL_PINMUX 0x00000004 | ||
98 | #define FEC_ECNTRL_ETHER_EN 0x00000002 | ||
99 | #define FEC_ECNTRL_RESET 0x00000001 | ||
100 | |||
101 | #define FEC_RCNTRL_BC_REJ 0x00000010 | ||
102 | #define FEC_RCNTRL_PROM 0x00000008 | ||
103 | #define FEC_RCNTRL_MII_MODE 0x00000004 | ||
104 | #define FEC_RCNTRL_DRT 0x00000002 | ||
105 | #define FEC_RCNTRL_LOOP 0x00000001 | ||
106 | |||
107 | #define FEC_TCNTRL_FDEN 0x00000004 | ||
108 | #define FEC_TCNTRL_HBC 0x00000002 | ||
109 | #define FEC_TCNTRL_GTS 0x00000001 | ||
110 | |||
111 | |||
112 | /* Make MII read/write commands for the FEC. | ||
113 | */ | ||
114 | #define mk_mii_read(REG) (0x60020000 | ((REG & 0x1f) << 18)) | ||
115 | #define mk_mii_write(REG, VAL) (0x50020000 | ((REG & 0x1f) << 18) | (VAL & 0xffff)) | ||
116 | #define mk_mii_end 0 | ||
117 | |||
118 | #define FEC_MII_LOOPS 10000 | ||
119 | |||
120 | /* | ||
121 | * Delay to wait for FEC reset command to complete (in us) | ||
122 | */ | ||
123 | #define FEC_RESET_DELAY 50 | ||
124 | |||
125 | static int whack_reset(fec_t * fecp) | ||
126 | { | ||
127 | int i; | ||
128 | |||
129 | FW(fecp, ecntrl, FEC_ECNTRL_PINMUX | FEC_ECNTRL_RESET); | ||
130 | for (i = 0; i < FEC_RESET_DELAY; i++) { | ||
131 | if ((FR(fecp, ecntrl) & FEC_ECNTRL_RESET) == 0) | ||
132 | return 0; /* OK */ | ||
133 | udelay(1); | ||
134 | } | ||
135 | |||
136 | return -1; | ||
137 | } | ||
138 | |||
139 | static int do_pd_setup(struct fs_enet_private *fep) | ||
140 | { | ||
141 | struct platform_device *pdev = to_platform_device(fep->dev); | ||
142 | struct resource *r; | ||
143 | |||
144 | /* Fill out IRQ field */ | ||
145 | fep->interrupt = platform_get_irq_byname(pdev,"interrupt"); | ||
146 | |||
147 | r = platform_get_resource_byname(pdev, IORESOURCE_MEM, "regs"); | ||
148 | fep->fec.fecp =(void*)r->start; | ||
149 | |||
150 | if(fep->fec.fecp == NULL) | ||
151 | return -EINVAL; | ||
152 | |||
153 | return 0; | ||
154 | |||
155 | } | ||
156 | |||
157 | #define FEC_NAPI_RX_EVENT_MSK (FEC_ENET_RXF | FEC_ENET_RXB) | ||
158 | #define FEC_RX_EVENT (FEC_ENET_RXF) | ||
159 | #define FEC_TX_EVENT (FEC_ENET_TXF) | ||
160 | #define FEC_ERR_EVENT_MSK (FEC_ENET_HBERR | FEC_ENET_BABR | \ | ||
161 | FEC_ENET_BABT | FEC_ENET_EBERR) | ||
162 | |||
163 | static int setup_data(struct net_device *dev) | ||
164 | { | ||
165 | struct fs_enet_private *fep = netdev_priv(dev); | ||
166 | |||
167 | if (do_pd_setup(fep) != 0) | ||
168 | return -EINVAL; | ||
169 | |||
170 | fep->fec.hthi = 0; | ||
171 | fep->fec.htlo = 0; | ||
172 | |||
173 | fep->ev_napi_rx = FEC_NAPI_RX_EVENT_MSK; | ||
174 | fep->ev_rx = FEC_RX_EVENT; | ||
175 | fep->ev_tx = FEC_TX_EVENT; | ||
176 | fep->ev_err = FEC_ERR_EVENT_MSK; | ||
177 | |||
178 | return 0; | ||
179 | } | ||
180 | |||
181 | static int allocate_bd(struct net_device *dev) | ||
182 | { | ||
183 | struct fs_enet_private *fep = netdev_priv(dev); | ||
184 | const struct fs_platform_info *fpi = fep->fpi; | ||
185 | |||
186 | fep->ring_base = dma_alloc_coherent(fep->dev, | ||
187 | (fpi->tx_ring + fpi->rx_ring) * | ||
188 | sizeof(cbd_t), &fep->ring_mem_addr, | ||
189 | GFP_KERNEL); | ||
190 | if (fep->ring_base == NULL) | ||
191 | return -ENOMEM; | ||
192 | |||
193 | return 0; | ||
194 | } | ||
195 | |||
196 | static void free_bd(struct net_device *dev) | ||
197 | { | ||
198 | struct fs_enet_private *fep = netdev_priv(dev); | ||
199 | const struct fs_platform_info *fpi = fep->fpi; | ||
200 | |||
201 | if(fep->ring_base) | ||
202 | dma_free_coherent(fep->dev, (fpi->tx_ring + fpi->rx_ring) | ||
203 | * sizeof(cbd_t), | ||
204 | fep->ring_base, | ||
205 | fep->ring_mem_addr); | ||
206 | } | ||
207 | |||
208 | static void cleanup_data(struct net_device *dev) | ||
209 | { | ||
210 | /* nothing */ | ||
211 | } | ||
212 | |||
213 | static void set_promiscuous_mode(struct net_device *dev) | ||
214 | { | ||
215 | struct fs_enet_private *fep = netdev_priv(dev); | ||
216 | fec_t *fecp = fep->fec.fecp; | ||
217 | |||
218 | FS(fecp, r_cntrl, FEC_RCNTRL_PROM); | ||
219 | } | ||
220 | |||
221 | static void set_multicast_start(struct net_device *dev) | ||
222 | { | ||
223 | struct fs_enet_private *fep = netdev_priv(dev); | ||
224 | |||
225 | fep->fec.hthi = 0; | ||
226 | fep->fec.htlo = 0; | ||
227 | } | ||
228 | |||
229 | static void set_multicast_one(struct net_device *dev, const u8 *mac) | ||
230 | { | ||
231 | struct fs_enet_private *fep = netdev_priv(dev); | ||
232 | int temp, hash_index, i, j; | ||
233 | u32 crc, csrVal; | ||
234 | u8 byte, msb; | ||
235 | |||
236 | crc = 0xffffffff; | ||
237 | for (i = 0; i < 6; i++) { | ||
238 | byte = mac[i]; | ||
239 | for (j = 0; j < 8; j++) { | ||
240 | msb = crc >> 31; | ||
241 | crc <<= 1; | ||
242 | if (msb ^ (byte & 0x1)) | ||
243 | crc ^= FEC_CRC_POLY; | ||
244 | byte >>= 1; | ||
245 | } | ||
246 | } | ||
247 | |||
248 | temp = (crc & 0x3f) >> 1; | ||
249 | hash_index = ((temp & 0x01) << 4) | | ||
250 | ((temp & 0x02) << 2) | | ||
251 | ((temp & 0x04)) | | ||
252 | ((temp & 0x08) >> 2) | | ||
253 | ((temp & 0x10) >> 4); | ||
254 | csrVal = 1 << hash_index; | ||
255 | if (crc & 1) | ||
256 | fep->fec.hthi |= csrVal; | ||
257 | else | ||
258 | fep->fec.htlo |= csrVal; | ||
259 | } | ||
260 | |||
261 | static void set_multicast_finish(struct net_device *dev) | ||
262 | { | ||
263 | struct fs_enet_private *fep = netdev_priv(dev); | ||
264 | fec_t *fecp = fep->fec.fecp; | ||
265 | |||
266 | /* if all multi or too many multicasts; just enable all */ | ||
267 | if ((dev->flags & IFF_ALLMULTI) != 0 || | ||
268 | dev->mc_count > FEC_MAX_MULTICAST_ADDRS) { | ||
269 | fep->fec.hthi = 0xffffffffU; | ||
270 | fep->fec.htlo = 0xffffffffU; | ||
271 | } | ||
272 | |||
273 | FC(fecp, r_cntrl, FEC_RCNTRL_PROM); | ||
274 | FW(fecp, hash_table_high, fep->fec.hthi); | ||
275 | FW(fecp, hash_table_low, fep->fec.htlo); | ||
276 | } | ||
277 | |||
278 | static void set_multicast_list(struct net_device *dev) | ||
279 | { | ||
280 | struct dev_mc_list *pmc; | ||
281 | |||
282 | if ((dev->flags & IFF_PROMISC) == 0) { | ||
283 | set_multicast_start(dev); | ||
284 | for (pmc = dev->mc_list; pmc != NULL; pmc = pmc->next) | ||
285 | set_multicast_one(dev, pmc->dmi_addr); | ||
286 | set_multicast_finish(dev); | ||
287 | } else | ||
288 | set_promiscuous_mode(dev); | ||
289 | } | ||
290 | |||
291 | static void restart(struct net_device *dev) | ||
292 | { | ||
293 | #ifdef CONFIG_DUET | ||
294 | immap_t *immap = fs_enet_immap; | ||
295 | u32 cptr; | ||
296 | #endif | ||
297 | struct fs_enet_private *fep = netdev_priv(dev); | ||
298 | fec_t *fecp = fep->fec.fecp; | ||
299 | const struct fs_platform_info *fpi = fep->fpi; | ||
300 | dma_addr_t rx_bd_base_phys, tx_bd_base_phys; | ||
301 | int r; | ||
302 | u32 addrhi, addrlo; | ||
303 | |||
304 | r = whack_reset(fep->fec.fecp); | ||
305 | if (r != 0) | ||
306 | printk(KERN_ERR DRV_MODULE_NAME | ||
307 | ": %s FEC Reset FAILED!\n", dev->name); | ||
308 | |||
309 | /* | ||
310 | * Set station address. | ||
311 | */ | ||
312 | addrhi = ((u32) dev->dev_addr[0] << 24) | | ||
313 | ((u32) dev->dev_addr[1] << 16) | | ||
314 | ((u32) dev->dev_addr[2] << 8) | | ||
315 | (u32) dev->dev_addr[3]; | ||
316 | addrlo = ((u32) dev->dev_addr[4] << 24) | | ||
317 | ((u32) dev->dev_addr[5] << 16); | ||
318 | FW(fecp, addr_low, addrhi); | ||
319 | FW(fecp, addr_high, addrlo); | ||
320 | |||
321 | /* | ||
322 | * Reset all multicast. | ||
323 | */ | ||
324 | FW(fecp, hash_table_high, fep->fec.hthi); | ||
325 | FW(fecp, hash_table_low, fep->fec.htlo); | ||
326 | |||
327 | /* | ||
328 | * Set maximum receive buffer size. | ||
329 | */ | ||
330 | FW(fecp, r_buff_size, PKT_MAXBLR_SIZE); | ||
331 | FW(fecp, r_hash, PKT_MAXBUF_SIZE); | ||
332 | |||
333 | /* get physical address */ | ||
334 | rx_bd_base_phys = fep->ring_mem_addr; | ||
335 | tx_bd_base_phys = rx_bd_base_phys + sizeof(cbd_t) * fpi->rx_ring; | ||
336 | |||
337 | /* | ||
338 | * Set receive and transmit descriptor base. | ||
339 | */ | ||
340 | FW(fecp, r_des_start, rx_bd_base_phys); | ||
341 | FW(fecp, x_des_start, tx_bd_base_phys); | ||
342 | |||
343 | fs_init_bds(dev); | ||
344 | |||
345 | /* | ||
346 | * Enable big endian and don't care about SDMA FC. | ||
347 | */ | ||
348 | FW(fecp, fun_code, 0x78000000); | ||
349 | |||
350 | /* | ||
351 | * Set MII speed. | ||
352 | */ | ||
353 | FW(fecp, mii_speed, fep->mii_bus->fec.mii_speed); | ||
354 | |||
355 | /* | ||
356 | * Clear any outstanding interrupt. | ||
357 | */ | ||
358 | FW(fecp, ievent, 0xffc0); | ||
359 | FW(fecp, ivec, (fep->interrupt / 2) << 29); | ||
360 | |||
361 | |||
362 | /* | ||
363 | * adjust to speed (only for DUET & RMII) | ||
364 | */ | ||
365 | #ifdef CONFIG_DUET | ||
366 | if (fpi->use_rmii) { | ||
367 | cptr = in_be32(&immap->im_cpm.cp_cptr); | ||
368 | switch (fs_get_fec_index(fpi->fs_no)) { | ||
369 | case 0: | ||
370 | cptr |= 0x100; | ||
371 | if (fep->speed == 10) | ||
372 | cptr |= 0x0000010; | ||
373 | else if (fep->speed == 100) | ||
374 | cptr &= ~0x0000010; | ||
375 | break; | ||
376 | case 1: | ||
377 | cptr |= 0x80; | ||
378 | if (fep->speed == 10) | ||
379 | cptr |= 0x0000008; | ||
380 | else if (fep->speed == 100) | ||
381 | cptr &= ~0x0000008; | ||
382 | break; | ||
383 | default: | ||
384 | BUG(); /* should never happen */ | ||
385 | break; | ||
386 | } | ||
387 | out_be32(&immap->im_cpm.cp_cptr, cptr); | ||
388 | } | ||
389 | #endif | ||
390 | |||
391 | FW(fecp, r_cntrl, FEC_RCNTRL_MII_MODE); /* MII enable */ | ||
392 | /* | ||
393 | * adjust to duplex mode | ||
394 | */ | ||
395 | if (fep->duplex) { | ||
396 | FC(fecp, r_cntrl, FEC_RCNTRL_DRT); | ||
397 | FS(fecp, x_cntrl, FEC_TCNTRL_FDEN); /* FD enable */ | ||
398 | } else { | ||
399 | FS(fecp, r_cntrl, FEC_RCNTRL_DRT); | ||
400 | FC(fecp, x_cntrl, FEC_TCNTRL_FDEN); /* FD disable */ | ||
401 | } | ||
402 | |||
403 | /* | ||
404 | * Enable interrupts we wish to service. | ||
405 | */ | ||
406 | FW(fecp, imask, FEC_ENET_TXF | FEC_ENET_TXB | | ||
407 | FEC_ENET_RXF | FEC_ENET_RXB); | ||
408 | |||
409 | /* | ||
410 | * And last, enable the transmit and receive processing. | ||
411 | */ | ||
412 | FW(fecp, ecntrl, FEC_ECNTRL_PINMUX | FEC_ECNTRL_ETHER_EN); | ||
413 | FW(fecp, r_des_active, 0x01000000); | ||
414 | } | ||
415 | |||
416 | static void stop(struct net_device *dev) | ||
417 | { | ||
418 | struct fs_enet_private *fep = netdev_priv(dev); | ||
419 | fec_t *fecp = fep->fec.fecp; | ||
420 | struct fs_enet_mii_bus *bus = fep->mii_bus; | ||
421 | const struct fs_mii_bus_info *bi = bus->bus_info; | ||
422 | int i; | ||
423 | |||
424 | if ((FR(fecp, ecntrl) & FEC_ECNTRL_ETHER_EN) == 0) | ||
425 | return; /* already down */ | ||
426 | |||
427 | FW(fecp, x_cntrl, 0x01); /* Graceful transmit stop */ | ||
428 | for (i = 0; ((FR(fecp, ievent) & 0x10000000) == 0) && | ||
429 | i < FEC_RESET_DELAY; i++) | ||
430 | udelay(1); | ||
431 | |||
432 | if (i == FEC_RESET_DELAY) | ||
433 | printk(KERN_WARNING DRV_MODULE_NAME | ||
434 | ": %s FEC timeout on graceful transmit stop\n", | ||
435 | dev->name); | ||
436 | /* | ||
437 | * Disable FEC. Let only MII interrupts. | ||
438 | */ | ||
439 | FW(fecp, imask, 0); | ||
440 | FC(fecp, ecntrl, FEC_ECNTRL_ETHER_EN); | ||
441 | |||
442 | fs_cleanup_bds(dev); | ||
443 | |||
444 | /* shut down FEC1? that's where the mii bus is */ | ||
445 | if (fep->fec.idx == 0 && bus->refs > 1 && bi->method == fsmii_fec) { | ||
446 | FS(fecp, r_cntrl, FEC_RCNTRL_MII_MODE); /* MII enable */ | ||
447 | FS(fecp, ecntrl, FEC_ECNTRL_PINMUX | FEC_ECNTRL_ETHER_EN); | ||
448 | FW(fecp, ievent, FEC_ENET_MII); | ||
449 | FW(fecp, mii_speed, bus->fec.mii_speed); | ||
450 | } | ||
451 | } | ||
452 | |||
453 | static void pre_request_irq(struct net_device *dev, int irq) | ||
454 | { | ||
455 | immap_t *immap = fs_enet_immap; | ||
456 | u32 siel; | ||
457 | |||
458 | /* SIU interrupt */ | ||
459 | if (irq >= SIU_IRQ0 && irq < SIU_LEVEL7) { | ||
460 | |||
461 | siel = in_be32(&immap->im_siu_conf.sc_siel); | ||
462 | if ((irq & 1) == 0) | ||
463 | siel |= (0x80000000 >> irq); | ||
464 | else | ||
465 | siel &= ~(0x80000000 >> (irq & ~1)); | ||
466 | out_be32(&immap->im_siu_conf.sc_siel, siel); | ||
467 | } | ||
468 | } | ||
469 | |||
470 | static void post_free_irq(struct net_device *dev, int irq) | ||
471 | { | ||
472 | /* nothing */ | ||
473 | } | ||
474 | |||
475 | static void napi_clear_rx_event(struct net_device *dev) | ||
476 | { | ||
477 | struct fs_enet_private *fep = netdev_priv(dev); | ||
478 | fec_t *fecp = fep->fec.fecp; | ||
479 | |||
480 | FW(fecp, ievent, FEC_NAPI_RX_EVENT_MSK); | ||
481 | } | ||
482 | |||
483 | static void napi_enable_rx(struct net_device *dev) | ||
484 | { | ||
485 | struct fs_enet_private *fep = netdev_priv(dev); | ||
486 | fec_t *fecp = fep->fec.fecp; | ||
487 | |||
488 | FS(fecp, imask, FEC_NAPI_RX_EVENT_MSK); | ||
489 | } | ||
490 | |||
491 | static void napi_disable_rx(struct net_device *dev) | ||
492 | { | ||
493 | struct fs_enet_private *fep = netdev_priv(dev); | ||
494 | fec_t *fecp = fep->fec.fecp; | ||
495 | |||
496 | FC(fecp, imask, FEC_NAPI_RX_EVENT_MSK); | ||
497 | } | ||
498 | |||
499 | static void rx_bd_done(struct net_device *dev) | ||
500 | { | ||
501 | struct fs_enet_private *fep = netdev_priv(dev); | ||
502 | fec_t *fecp = fep->fec.fecp; | ||
503 | |||
504 | FW(fecp, r_des_active, 0x01000000); | ||
505 | } | ||
506 | |||
507 | static void tx_kickstart(struct net_device *dev) | ||
508 | { | ||
509 | struct fs_enet_private *fep = netdev_priv(dev); | ||
510 | fec_t *fecp = fep->fec.fecp; | ||
511 | |||
512 | FW(fecp, x_des_active, 0x01000000); | ||
513 | } | ||
514 | |||
515 | static u32 get_int_events(struct net_device *dev) | ||
516 | { | ||
517 | struct fs_enet_private *fep = netdev_priv(dev); | ||
518 | fec_t *fecp = fep->fec.fecp; | ||
519 | |||
520 | return FR(fecp, ievent) & FR(fecp, imask); | ||
521 | } | ||
522 | |||
523 | static void clear_int_events(struct net_device *dev, u32 int_events) | ||
524 | { | ||
525 | struct fs_enet_private *fep = netdev_priv(dev); | ||
526 | fec_t *fecp = fep->fec.fecp; | ||
527 | |||
528 | FW(fecp, ievent, int_events); | ||
529 | } | ||
530 | |||
531 | static void ev_error(struct net_device *dev, u32 int_events) | ||
532 | { | ||
533 | printk(KERN_WARNING DRV_MODULE_NAME | ||
534 | ": %s FEC ERROR(s) 0x%x\n", dev->name, int_events); | ||
535 | } | ||
536 | |||
537 | int get_regs(struct net_device *dev, void *p, int *sizep) | ||
538 | { | ||
539 | struct fs_enet_private *fep = netdev_priv(dev); | ||
540 | |||
541 | if (*sizep < sizeof(fec_t)) | ||
542 | return -EINVAL; | ||
543 | |||
544 | memcpy_fromio(p, fep->fec.fecp, sizeof(fec_t)); | ||
545 | |||
546 | return 0; | ||
547 | } | ||
548 | |||
549 | int get_regs_len(struct net_device *dev) | ||
550 | { | ||
551 | return sizeof(fec_t); | ||
552 | } | ||
553 | |||
554 | void tx_restart(struct net_device *dev) | ||
555 | { | ||
556 | /* nothing */ | ||
557 | } | ||
558 | |||
559 | /*************************************************************************/ | ||
560 | |||
561 | const struct fs_ops fs_fec_ops = { | ||
562 | .setup_data = setup_data, | ||
563 | .cleanup_data = cleanup_data, | ||
564 | .set_multicast_list = set_multicast_list, | ||
565 | .restart = restart, | ||
566 | .stop = stop, | ||
567 | .pre_request_irq = pre_request_irq, | ||
568 | .post_free_irq = post_free_irq, | ||
569 | .napi_clear_rx_event = napi_clear_rx_event, | ||
570 | .napi_enable_rx = napi_enable_rx, | ||
571 | .napi_disable_rx = napi_disable_rx, | ||
572 | .rx_bd_done = rx_bd_done, | ||
573 | .tx_kickstart = tx_kickstart, | ||
574 | .get_int_events = get_int_events, | ||
575 | .clear_int_events = clear_int_events, | ||
576 | .ev_error = ev_error, | ||
577 | .get_regs = get_regs, | ||
578 | .get_regs_len = get_regs_len, | ||
579 | .tx_restart = tx_restart, | ||
580 | .allocate_bd = allocate_bd, | ||
581 | .free_bd = free_bd, | ||
582 | }; | ||
583 | |||
584 | /***********************************************************************/ | ||
585 | |||
586 | static int mii_read(struct fs_enet_mii_bus *bus, int phy_id, int location) | ||
587 | { | ||
588 | fec_t *fecp = bus->fec.fecp; | ||
589 | int i, ret = -1; | ||
590 | |||
591 | if ((FR(fecp, r_cntrl) & FEC_RCNTRL_MII_MODE) == 0) | ||
592 | BUG(); | ||
593 | |||
594 | /* Add PHY address to register command. */ | ||
595 | FW(fecp, mii_data, (phy_id << 23) | mk_mii_read(location)); | ||
596 | |||
597 | for (i = 0; i < FEC_MII_LOOPS; i++) | ||
598 | if ((FR(fecp, ievent) & FEC_ENET_MII) != 0) | ||
599 | break; | ||
600 | |||
601 | if (i < FEC_MII_LOOPS) { | ||
602 | FW(fecp, ievent, FEC_ENET_MII); | ||
603 | ret = FR(fecp, mii_data) & 0xffff; | ||
604 | } | ||
605 | |||
606 | return ret; | ||
607 | } | ||
608 | |||
609 | static void mii_write(struct fs_enet_mii_bus *bus, int phy_id, int location, int value) | ||
610 | { | ||
611 | fec_t *fecp = bus->fec.fecp; | ||
612 | int i; | ||
613 | |||
614 | /* this must never happen */ | ||
615 | if ((FR(fecp, r_cntrl) & FEC_RCNTRL_MII_MODE) == 0) | ||
616 | BUG(); | ||
617 | |||
618 | /* Add PHY address to register command. */ | ||
619 | FW(fecp, mii_data, (phy_id << 23) | mk_mii_write(location, value)); | ||
620 | |||
621 | for (i = 0; i < FEC_MII_LOOPS; i++) | ||
622 | if ((FR(fecp, ievent) & FEC_ENET_MII) != 0) | ||
623 | break; | ||
624 | |||
625 | if (i < FEC_MII_LOOPS) | ||
626 | FW(fecp, ievent, FEC_ENET_MII); | ||
627 | } | ||
628 | |||
629 | int fs_mii_fec_init(struct fs_enet_mii_bus *bus) | ||
630 | { | ||
631 | bd_t *bd = (bd_t *)__res; | ||
632 | const struct fs_mii_bus_info *bi = bus->bus_info; | ||
633 | fec_t *fecp; | ||
634 | |||
635 | if (bi->id != 0) | ||
636 | return -1; | ||
637 | |||
638 | bus->fec.fecp = &((immap_t *)fs_enet_immap)->im_cpm.cp_fec; | ||
639 | bus->fec.mii_speed = ((((bd->bi_intfreq + 4999999) / 2500000) / 2) | ||
640 | & 0x3F) << 1; | ||
641 | |||
642 | fecp = bus->fec.fecp; | ||
643 | |||
644 | FS(fecp, r_cntrl, FEC_RCNTRL_MII_MODE); /* MII enable */ | ||
645 | FS(fecp, ecntrl, FEC_ECNTRL_PINMUX | FEC_ECNTRL_ETHER_EN); | ||
646 | FW(fecp, ievent, FEC_ENET_MII); | ||
647 | FW(fecp, mii_speed, bus->fec.mii_speed); | ||
648 | |||
649 | bus->mii_read = mii_read; | ||
650 | bus->mii_write = mii_write; | ||
651 | |||
652 | return 0; | ||
653 | } | ||
diff --git a/drivers/net/fs_enet/mac-scc.c b/drivers/net/fs_enet/mac-scc.c new file mode 100644 index 000000000000..d8c6e9cadcf5 --- /dev/null +++ b/drivers/net/fs_enet/mac-scc.c | |||
@@ -0,0 +1,524 @@ | |||
1 | /* | ||
2 | * Ethernet on Serial Communications Controller (SCC) driver for Motorola MPC8xx and MPC82xx. | ||
3 | * | ||
4 | * Copyright (c) 2003 Intracom S.A. | ||
5 | * by Pantelis Antoniou <panto@intracom.gr> | ||
6 | * | ||
7 | * 2005 (c) MontaVista Software, Inc. | ||
8 | * Vitaly Bordug <vbordug@ru.mvista.com> | ||
9 | * | ||
10 | * This file is licensed under the terms of the GNU General Public License | ||
11 | * version 2. This program is licensed "as is" without any warranty of any | ||
12 | * kind, whether express or implied. | ||
13 | */ | ||
14 | |||
15 | #include <linux/config.h> | ||
16 | #include <linux/module.h> | ||
17 | #include <linux/kernel.h> | ||
18 | #include <linux/types.h> | ||
19 | #include <linux/sched.h> | ||
20 | #include <linux/string.h> | ||
21 | #include <linux/ptrace.h> | ||
22 | #include <linux/errno.h> | ||
23 | #include <linux/ioport.h> | ||
24 | #include <linux/slab.h> | ||
25 | #include <linux/interrupt.h> | ||
26 | #include <linux/pci.h> | ||
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> | ||
37 | |||
38 | #include <asm/irq.h> | ||
39 | #include <asm/uaccess.h> | ||
40 | |||
41 | #ifdef CONFIG_8xx | ||
42 | #include <asm/8xx_immap.h> | ||
43 | #include <asm/pgtable.h> | ||
44 | #include <asm/mpc8xx.h> | ||
45 | #include <asm/commproc.h> | ||
46 | #endif | ||
47 | |||
48 | #include "fs_enet.h" | ||
49 | |||
50 | /*************************************************/ | ||
51 | |||
52 | #if defined(CONFIG_CPM1) | ||
53 | /* for a 8xx __raw_xxx's are sufficient */ | ||
54 | #define __fs_out32(addr, x) __raw_writel(x, addr) | ||
55 | #define __fs_out16(addr, x) __raw_writew(x, addr) | ||
56 | #define __fs_out8(addr, x) __raw_writeb(x, addr) | ||
57 | #define __fs_in32(addr) __raw_readl(addr) | ||
58 | #define __fs_in16(addr) __raw_readw(addr) | ||
59 | #define __fs_in8(addr) __raw_readb(addr) | ||
60 | #else | ||
61 | /* for others play it safe */ | ||
62 | #define __fs_out32(addr, x) out_be32(addr, x) | ||
63 | #define __fs_out16(addr, x) out_be16(addr, x) | ||
64 | #define __fs_in32(addr) in_be32(addr) | ||
65 | #define __fs_in16(addr) in_be16(addr) | ||
66 | #endif | ||
67 | |||
68 | /* write, read, set bits, clear bits */ | ||
69 | #define W32(_p, _m, _v) __fs_out32(&(_p)->_m, (_v)) | ||
70 | #define R32(_p, _m) __fs_in32(&(_p)->_m) | ||
71 | #define S32(_p, _m, _v) W32(_p, _m, R32(_p, _m) | (_v)) | ||
72 | #define C32(_p, _m, _v) W32(_p, _m, R32(_p, _m) & ~(_v)) | ||
73 | |||
74 | #define W16(_p, _m, _v) __fs_out16(&(_p)->_m, (_v)) | ||
75 | #define R16(_p, _m) __fs_in16(&(_p)->_m) | ||
76 | #define S16(_p, _m, _v) W16(_p, _m, R16(_p, _m) | (_v)) | ||
77 | #define C16(_p, _m, _v) W16(_p, _m, R16(_p, _m) & ~(_v)) | ||
78 | |||
79 | #define W8(_p, _m, _v) __fs_out8(&(_p)->_m, (_v)) | ||
80 | #define R8(_p, _m) __fs_in8(&(_p)->_m) | ||
81 | #define S8(_p, _m, _v) W8(_p, _m, R8(_p, _m) | (_v)) | ||
82 | #define C8(_p, _m, _v) W8(_p, _m, R8(_p, _m) & ~(_v)) | ||
83 | |||
84 | #define SCC_MAX_MULTICAST_ADDRS 64 | ||
85 | |||
86 | /* | ||
87 | * Delay to wait for SCC reset command to complete (in us) | ||
88 | */ | ||
89 | #define SCC_RESET_DELAY 50 | ||
90 | #define MAX_CR_CMD_LOOPS 10000 | ||
91 | |||
92 | static inline int scc_cr_cmd(struct fs_enet_private *fep, u32 op) | ||
93 | { | ||
94 | cpm8xx_t *cpmp = &((immap_t *)fs_enet_immap)->im_cpm; | ||
95 | u32 v, ch; | ||
96 | int i = 0; | ||
97 | |||
98 | ch = fep->scc.idx << 2; | ||
99 | v = mk_cr_cmd(ch, op); | ||
100 | W16(cpmp, cp_cpcr, v | CPM_CR_FLG); | ||
101 | for (i = 0; i < MAX_CR_CMD_LOOPS; i++) | ||
102 | if ((R16(cpmp, cp_cpcr) & CPM_CR_FLG) == 0) | ||
103 | break; | ||
104 | |||
105 | if (i >= MAX_CR_CMD_LOOPS) { | ||
106 | printk(KERN_ERR "%s(): Not able to issue CPM command\n", | ||
107 | __FUNCTION__); | ||
108 | return 1; | ||
109 | } | ||
110 | return 0; | ||
111 | } | ||
112 | |||
113 | static int do_pd_setup(struct fs_enet_private *fep) | ||
114 | { | ||
115 | struct platform_device *pdev = to_platform_device(fep->dev); | ||
116 | struct resource *r; | ||
117 | |||
118 | /* Fill out IRQ field */ | ||
119 | fep->interrupt = platform_get_irq_byname(pdev, "interrupt"); | ||
120 | |||
121 | r = platform_get_resource_byname(pdev, IORESOURCE_MEM, "regs"); | ||
122 | fep->scc.sccp = (void *)r->start; | ||
123 | |||
124 | if (fep->scc.sccp == NULL) | ||
125 | return -EINVAL; | ||
126 | |||
127 | r = platform_get_resource_byname(pdev, IORESOURCE_MEM, "pram"); | ||
128 | fep->scc.ep = (void *)r->start; | ||
129 | |||
130 | if (fep->scc.ep == NULL) | ||
131 | return -EINVAL; | ||
132 | |||
133 | return 0; | ||
134 | } | ||
135 | |||
136 | #define SCC_NAPI_RX_EVENT_MSK (SCCE_ENET_RXF | SCCE_ENET_RXB) | ||
137 | #define SCC_RX_EVENT (SCCE_ENET_RXF) | ||
138 | #define SCC_TX_EVENT (SCCE_ENET_TXB) | ||
139 | #define SCC_ERR_EVENT_MSK (SCCE_ENET_TXE | SCCE_ENET_BSY) | ||
140 | |||
141 | static int setup_data(struct net_device *dev) | ||
142 | { | ||
143 | struct fs_enet_private *fep = netdev_priv(dev); | ||
144 | const struct fs_platform_info *fpi = fep->fpi; | ||
145 | |||
146 | fep->scc.idx = fs_get_scc_index(fpi->fs_no); | ||
147 | if ((unsigned int)fep->fcc.idx > 4) /* max 4 SCCs */ | ||
148 | return -EINVAL; | ||
149 | |||
150 | do_pd_setup(fep); | ||
151 | |||
152 | fep->scc.hthi = 0; | ||
153 | fep->scc.htlo = 0; | ||
154 | |||
155 | fep->ev_napi_rx = SCC_NAPI_RX_EVENT_MSK; | ||
156 | fep->ev_rx = SCC_RX_EVENT; | ||
157 | fep->ev_tx = SCC_TX_EVENT; | ||
158 | fep->ev_err = SCC_ERR_EVENT_MSK; | ||
159 | |||
160 | return 0; | ||
161 | } | ||
162 | |||
163 | static int allocate_bd(struct net_device *dev) | ||
164 | { | ||
165 | struct fs_enet_private *fep = netdev_priv(dev); | ||
166 | const struct fs_platform_info *fpi = fep->fpi; | ||
167 | |||
168 | fep->ring_mem_addr = cpm_dpalloc((fpi->tx_ring + fpi->rx_ring) * | ||
169 | sizeof(cbd_t), 8); | ||
170 | if (IS_DPERR(fep->ring_mem_addr)) | ||
171 | return -ENOMEM; | ||
172 | |||
173 | fep->ring_base = cpm_dpram_addr(fep->ring_mem_addr); | ||
174 | |||
175 | return 0; | ||
176 | } | ||
177 | |||
178 | static void free_bd(struct net_device *dev) | ||
179 | { | ||
180 | struct fs_enet_private *fep = netdev_priv(dev); | ||
181 | |||
182 | if (fep->ring_base) | ||
183 | cpm_dpfree(fep->ring_mem_addr); | ||
184 | } | ||
185 | |||
186 | static void cleanup_data(struct net_device *dev) | ||
187 | { | ||
188 | /* nothing */ | ||
189 | } | ||
190 | |||
191 | static void set_promiscuous_mode(struct net_device *dev) | ||
192 | { | ||
193 | struct fs_enet_private *fep = netdev_priv(dev); | ||
194 | scc_t *sccp = fep->scc.sccp; | ||
195 | |||
196 | S16(sccp, scc_psmr, SCC_PSMR_PRO); | ||
197 | } | ||
198 | |||
199 | static void set_multicast_start(struct net_device *dev) | ||
200 | { | ||
201 | struct fs_enet_private *fep = netdev_priv(dev); | ||
202 | scc_enet_t *ep = fep->scc.ep; | ||
203 | |||
204 | W16(ep, sen_gaddr1, 0); | ||
205 | W16(ep, sen_gaddr2, 0); | ||
206 | W16(ep, sen_gaddr3, 0); | ||
207 | W16(ep, sen_gaddr4, 0); | ||
208 | } | ||
209 | |||
210 | static void set_multicast_one(struct net_device *dev, const u8 * mac) | ||
211 | { | ||
212 | struct fs_enet_private *fep = netdev_priv(dev); | ||
213 | scc_enet_t *ep = fep->scc.ep; | ||
214 | u16 taddrh, taddrm, taddrl; | ||
215 | |||
216 | taddrh = ((u16) mac[5] << 8) | mac[4]; | ||
217 | taddrm = ((u16) mac[3] << 8) | mac[2]; | ||
218 | taddrl = ((u16) mac[1] << 8) | mac[0]; | ||
219 | |||
220 | W16(ep, sen_taddrh, taddrh); | ||
221 | W16(ep, sen_taddrm, taddrm); | ||
222 | W16(ep, sen_taddrl, taddrl); | ||
223 | scc_cr_cmd(fep, CPM_CR_SET_GADDR); | ||
224 | } | ||
225 | |||
226 | static void set_multicast_finish(struct net_device *dev) | ||
227 | { | ||
228 | struct fs_enet_private *fep = netdev_priv(dev); | ||
229 | scc_t *sccp = fep->scc.sccp; | ||
230 | scc_enet_t *ep = fep->scc.ep; | ||
231 | |||
232 | /* clear promiscuous always */ | ||
233 | C16(sccp, scc_psmr, SCC_PSMR_PRO); | ||
234 | |||
235 | /* if all multi or too many multicasts; just enable all */ | ||
236 | if ((dev->flags & IFF_ALLMULTI) != 0 || | ||
237 | dev->mc_count > SCC_MAX_MULTICAST_ADDRS) { | ||
238 | |||
239 | W16(ep, sen_gaddr1, 0xffff); | ||
240 | W16(ep, sen_gaddr2, 0xffff); | ||
241 | W16(ep, sen_gaddr3, 0xffff); | ||
242 | W16(ep, sen_gaddr4, 0xffff); | ||
243 | } | ||
244 | } | ||
245 | |||
246 | static void set_multicast_list(struct net_device *dev) | ||
247 | { | ||
248 | struct dev_mc_list *pmc; | ||
249 | |||
250 | if ((dev->flags & IFF_PROMISC) == 0) { | ||
251 | set_multicast_start(dev); | ||
252 | for (pmc = dev->mc_list; pmc != NULL; pmc = pmc->next) | ||
253 | set_multicast_one(dev, pmc->dmi_addr); | ||
254 | set_multicast_finish(dev); | ||
255 | } else | ||
256 | set_promiscuous_mode(dev); | ||
257 | } | ||
258 | |||
259 | /* | ||
260 | * This function is called to start or restart the FEC during a link | ||
261 | * change. This only happens when switching between half and full | ||
262 | * duplex. | ||
263 | */ | ||
264 | static void restart(struct net_device *dev) | ||
265 | { | ||
266 | struct fs_enet_private *fep = netdev_priv(dev); | ||
267 | scc_t *sccp = fep->scc.sccp; | ||
268 | scc_enet_t *ep = fep->scc.ep; | ||
269 | const struct fs_platform_info *fpi = fep->fpi; | ||
270 | u16 paddrh, paddrm, paddrl; | ||
271 | const unsigned char *mac; | ||
272 | int i; | ||
273 | |||
274 | C32(sccp, scc_gsmrl, SCC_GSMRL_ENR | SCC_GSMRL_ENT); | ||
275 | |||
276 | /* clear everything (slow & steady does it) */ | ||
277 | for (i = 0; i < sizeof(*ep); i++) | ||
278 | __fs_out8((char *)ep + i, 0); | ||
279 | |||
280 | /* point to bds */ | ||
281 | W16(ep, sen_genscc.scc_rbase, fep->ring_mem_addr); | ||
282 | W16(ep, sen_genscc.scc_tbase, | ||
283 | fep->ring_mem_addr + sizeof(cbd_t) * fpi->rx_ring); | ||
284 | |||
285 | /* Initialize function code registers for big-endian. | ||
286 | */ | ||
287 | W8(ep, sen_genscc.scc_rfcr, SCC_EB); | ||
288 | W8(ep, sen_genscc.scc_tfcr, SCC_EB); | ||
289 | |||
290 | /* Set maximum bytes per receive buffer. | ||
291 | * This appears to be an Ethernet frame size, not the buffer | ||
292 | * fragment size. It must be a multiple of four. | ||
293 | */ | ||
294 | W16(ep, sen_genscc.scc_mrblr, 0x5f0); | ||
295 | |||
296 | /* Set CRC preset and mask. | ||
297 | */ | ||
298 | W32(ep, sen_cpres, 0xffffffff); | ||
299 | W32(ep, sen_cmask, 0xdebb20e3); | ||
300 | |||
301 | W32(ep, sen_crcec, 0); /* CRC Error counter */ | ||
302 | W32(ep, sen_alec, 0); /* alignment error counter */ | ||
303 | W32(ep, sen_disfc, 0); /* discard frame counter */ | ||
304 | |||
305 | W16(ep, sen_pads, 0x8888); /* Tx short frame pad character */ | ||
306 | W16(ep, sen_retlim, 15); /* Retry limit threshold */ | ||
307 | |||
308 | W16(ep, sen_maxflr, 0x5ee); /* maximum frame length register */ | ||
309 | |||
310 | W16(ep, sen_minflr, PKT_MINBUF_SIZE); /* minimum frame length register */ | ||
311 | |||
312 | W16(ep, sen_maxd1, 0x000005f0); /* maximum DMA1 length */ | ||
313 | W16(ep, sen_maxd2, 0x000005f0); /* maximum DMA2 length */ | ||
314 | |||
315 | /* Clear hash tables. | ||
316 | */ | ||
317 | W16(ep, sen_gaddr1, 0); | ||
318 | W16(ep, sen_gaddr2, 0); | ||
319 | W16(ep, sen_gaddr3, 0); | ||
320 | W16(ep, sen_gaddr4, 0); | ||
321 | W16(ep, sen_iaddr1, 0); | ||
322 | W16(ep, sen_iaddr2, 0); | ||
323 | W16(ep, sen_iaddr3, 0); | ||
324 | W16(ep, sen_iaddr4, 0); | ||
325 | |||
326 | /* set address | ||
327 | */ | ||
328 | mac = dev->dev_addr; | ||
329 | paddrh = ((u16) mac[5] << 8) | mac[4]; | ||
330 | paddrm = ((u16) mac[3] << 8) | mac[2]; | ||
331 | paddrl = ((u16) mac[1] << 8) | mac[0]; | ||
332 | |||
333 | W16(ep, sen_paddrh, paddrh); | ||
334 | W16(ep, sen_paddrm, paddrm); | ||
335 | W16(ep, sen_paddrl, paddrl); | ||
336 | |||
337 | W16(ep, sen_pper, 0); | ||
338 | W16(ep, sen_taddrl, 0); | ||
339 | W16(ep, sen_taddrm, 0); | ||
340 | W16(ep, sen_taddrh, 0); | ||
341 | |||
342 | fs_init_bds(dev); | ||
343 | |||
344 | scc_cr_cmd(fep, CPM_CR_INIT_TRX); | ||
345 | |||
346 | W16(sccp, scc_scce, 0xffff); | ||
347 | |||
348 | /* Enable interrupts we wish to service. | ||
349 | */ | ||
350 | W16(sccp, scc_sccm, SCCE_ENET_TXE | SCCE_ENET_RXF | SCCE_ENET_TXB); | ||
351 | |||
352 | /* Set GSMR_H to enable all normal operating modes. | ||
353 | * Set GSMR_L to enable Ethernet to MC68160. | ||
354 | */ | ||
355 | W32(sccp, scc_gsmrh, 0); | ||
356 | W32(sccp, scc_gsmrl, | ||
357 | SCC_GSMRL_TCI | SCC_GSMRL_TPL_48 | SCC_GSMRL_TPP_10 | | ||
358 | SCC_GSMRL_MODE_ENET); | ||
359 | |||
360 | /* Set sync/delimiters. | ||
361 | */ | ||
362 | W16(sccp, scc_dsr, 0xd555); | ||
363 | |||
364 | /* Set processing mode. Use Ethernet CRC, catch broadcast, and | ||
365 | * start frame search 22 bit times after RENA. | ||
366 | */ | ||
367 | W16(sccp, scc_psmr, SCC_PSMR_ENCRC | SCC_PSMR_NIB22); | ||
368 | |||
369 | /* Set full duplex mode if needed */ | ||
370 | if (fep->duplex) | ||
371 | S16(sccp, scc_psmr, SCC_PSMR_LPB | SCC_PSMR_FDE); | ||
372 | |||
373 | S32(sccp, scc_gsmrl, SCC_GSMRL_ENR | SCC_GSMRL_ENT); | ||
374 | } | ||
375 | |||
376 | static void stop(struct net_device *dev) | ||
377 | { | ||
378 | struct fs_enet_private *fep = netdev_priv(dev); | ||
379 | scc_t *sccp = fep->scc.sccp; | ||
380 | int i; | ||
381 | |||
382 | for (i = 0; (R16(sccp, scc_sccm) == 0) && i < SCC_RESET_DELAY; i++) | ||
383 | udelay(1); | ||
384 | |||
385 | if (i == SCC_RESET_DELAY) | ||
386 | printk(KERN_WARNING DRV_MODULE_NAME | ||
387 | ": %s SCC timeout on graceful transmit stop\n", | ||
388 | dev->name); | ||
389 | |||
390 | W16(sccp, scc_sccm, 0); | ||
391 | C32(sccp, scc_gsmrl, SCC_GSMRL_ENR | SCC_GSMRL_ENT); | ||
392 | |||
393 | fs_cleanup_bds(dev); | ||
394 | } | ||
395 | |||
396 | static void pre_request_irq(struct net_device *dev, int irq) | ||
397 | { | ||
398 | immap_t *immap = fs_enet_immap; | ||
399 | u32 siel; | ||
400 | |||
401 | /* SIU interrupt */ | ||
402 | if (irq >= SIU_IRQ0 && irq < SIU_LEVEL7) { | ||
403 | |||
404 | siel = in_be32(&immap->im_siu_conf.sc_siel); | ||
405 | if ((irq & 1) == 0) | ||
406 | siel |= (0x80000000 >> irq); | ||
407 | else | ||
408 | siel &= ~(0x80000000 >> (irq & ~1)); | ||
409 | out_be32(&immap->im_siu_conf.sc_siel, siel); | ||
410 | } | ||
411 | } | ||
412 | |||
413 | static void post_free_irq(struct net_device *dev, int irq) | ||
414 | { | ||
415 | /* nothing */ | ||
416 | } | ||
417 | |||
418 | static void napi_clear_rx_event(struct net_device *dev) | ||
419 | { | ||
420 | struct fs_enet_private *fep = netdev_priv(dev); | ||
421 | scc_t *sccp = fep->scc.sccp; | ||
422 | |||
423 | W16(sccp, scc_scce, SCC_NAPI_RX_EVENT_MSK); | ||
424 | } | ||
425 | |||
426 | static void napi_enable_rx(struct net_device *dev) | ||
427 | { | ||
428 | struct fs_enet_private *fep = netdev_priv(dev); | ||
429 | scc_t *sccp = fep->scc.sccp; | ||
430 | |||
431 | S16(sccp, scc_sccm, SCC_NAPI_RX_EVENT_MSK); | ||
432 | } | ||
433 | |||
434 | static void napi_disable_rx(struct net_device *dev) | ||
435 | { | ||
436 | struct fs_enet_private *fep = netdev_priv(dev); | ||
437 | scc_t *sccp = fep->scc.sccp; | ||
438 | |||
439 | C16(sccp, scc_sccm, SCC_NAPI_RX_EVENT_MSK); | ||
440 | } | ||
441 | |||
442 | static void rx_bd_done(struct net_device *dev) | ||
443 | { | ||
444 | /* nothing */ | ||
445 | } | ||
446 | |||
447 | static void tx_kickstart(struct net_device *dev) | ||
448 | { | ||
449 | /* nothing */ | ||
450 | } | ||
451 | |||
452 | static u32 get_int_events(struct net_device *dev) | ||
453 | { | ||
454 | struct fs_enet_private *fep = netdev_priv(dev); | ||
455 | scc_t *sccp = fep->scc.sccp; | ||
456 | |||
457 | return (u32) R16(sccp, scc_scce); | ||
458 | } | ||
459 | |||
460 | static void clear_int_events(struct net_device *dev, u32 int_events) | ||
461 | { | ||
462 | struct fs_enet_private *fep = netdev_priv(dev); | ||
463 | scc_t *sccp = fep->scc.sccp; | ||
464 | |||
465 | W16(sccp, scc_scce, int_events & 0xffff); | ||
466 | } | ||
467 | |||
468 | static void ev_error(struct net_device *dev, u32 int_events) | ||
469 | { | ||
470 | printk(KERN_WARNING DRV_MODULE_NAME | ||
471 | ": %s SCC ERROR(s) 0x%x\n", dev->name, int_events); | ||
472 | } | ||
473 | |||
474 | static int get_regs(struct net_device *dev, void *p, int *sizep) | ||
475 | { | ||
476 | struct fs_enet_private *fep = netdev_priv(dev); | ||
477 | |||
478 | if (*sizep < sizeof(scc_t) + sizeof(scc_enet_t)) | ||
479 | return -EINVAL; | ||
480 | |||
481 | memcpy_fromio(p, fep->scc.sccp, sizeof(scc_t)); | ||
482 | p = (char *)p + sizeof(scc_t); | ||
483 | |||
484 | memcpy_fromio(p, fep->scc.ep, sizeof(scc_enet_t)); | ||
485 | |||
486 | return 0; | ||
487 | } | ||
488 | |||
489 | static int get_regs_len(struct net_device *dev) | ||
490 | { | ||
491 | return sizeof(scc_t) + sizeof(scc_enet_t); | ||
492 | } | ||
493 | |||
494 | static void tx_restart(struct net_device *dev) | ||
495 | { | ||
496 | struct fs_enet_private *fep = netdev_priv(dev); | ||
497 | |||
498 | scc_cr_cmd(fep, CPM_CR_RESTART_TX); | ||
499 | } | ||
500 | |||
501 | /*************************************************************************/ | ||
502 | |||
503 | const struct fs_ops fs_scc_ops = { | ||
504 | .setup_data = setup_data, | ||
505 | .cleanup_data = cleanup_data, | ||
506 | .set_multicast_list = set_multicast_list, | ||
507 | .restart = restart, | ||
508 | .stop = stop, | ||
509 | .pre_request_irq = pre_request_irq, | ||
510 | .post_free_irq = post_free_irq, | ||
511 | .napi_clear_rx_event = napi_clear_rx_event, | ||
512 | .napi_enable_rx = napi_enable_rx, | ||
513 | .napi_disable_rx = napi_disable_rx, | ||
514 | .rx_bd_done = rx_bd_done, | ||
515 | .tx_kickstart = tx_kickstart, | ||
516 | .get_int_events = get_int_events, | ||
517 | .clear_int_events = clear_int_events, | ||
518 | .ev_error = ev_error, | ||
519 | .get_regs = get_regs, | ||
520 | .get_regs_len = get_regs_len, | ||
521 | .tx_restart = tx_restart, | ||
522 | .allocate_bd = allocate_bd, | ||
523 | .free_bd = free_bd, | ||
524 | }; | ||
diff --git a/drivers/net/fs_enet/mii-bitbang.c b/drivers/net/fs_enet/mii-bitbang.c new file mode 100644 index 000000000000..24a5e2e23d18 --- /dev/null +++ b/drivers/net/fs_enet/mii-bitbang.c | |||
@@ -0,0 +1,405 @@ | |||
1 | /* | ||
2 | * Combined Ethernet driver for Motorola MPC8xx and MPC82xx. | ||
3 | * | ||
4 | * Copyright (c) 2003 Intracom S.A. | ||
5 | * by Pantelis Antoniou <panto@intracom.gr> | ||
6 | * | ||
7 | * 2005 (c) MontaVista Software, Inc. | ||
8 | * Vitaly Bordug <vbordug@ru.mvista.com> | ||
9 | * | ||
10 | * This file is licensed under the terms of the GNU General Public License | ||
11 | * version 2. This program is licensed "as is" without any warranty of any | ||
12 | * kind, whether express or implied. | ||
13 | */ | ||
14 | |||
15 | |||
16 | #include <linux/config.h> | ||
17 | #include <linux/module.h> | ||
18 | #include <linux/types.h> | ||
19 | #include <linux/kernel.h> | ||
20 | #include <linux/sched.h> | ||
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> | ||
27 | #include <linux/pci.h> | ||
28 | #include <linux/init.h> | ||
29 | #include <linux/delay.h> | ||
30 | #include <linux/netdevice.h> | ||
31 | #include <linux/etherdevice.h> | ||
32 | #include <linux/skbuff.h> | ||
33 | #include <linux/spinlock.h> | ||
34 | #include <linux/mii.h> | ||
35 | #include <linux/ethtool.h> | ||
36 | #include <linux/bitops.h> | ||
37 | |||
38 | #include <asm/pgtable.h> | ||
39 | #include <asm/irq.h> | ||
40 | #include <asm/uaccess.h> | ||
41 | |||
42 | #include "fs_enet.h" | ||
43 | |||
44 | #ifdef CONFIG_8xx | ||
45 | static int bitbang_prep_bit(u8 **dirp, u8 **datp, u8 *mskp, int port, int bit) | ||
46 | { | ||
47 | immap_t *im = (immap_t *)fs_enet_immap; | ||
48 | void *dir, *dat, *ppar; | ||
49 | int adv; | ||
50 | u8 msk; | ||
51 | |||
52 | switch (port) { | ||
53 | case fsiop_porta: | ||
54 | dir = &im->im_ioport.iop_padir; | ||
55 | dat = &im->im_ioport.iop_padat; | ||
56 | ppar = &im->im_ioport.iop_papar; | ||
57 | break; | ||
58 | |||
59 | case fsiop_portb: | ||
60 | dir = &im->im_cpm.cp_pbdir; | ||
61 | dat = &im->im_cpm.cp_pbdat; | ||
62 | ppar = &im->im_cpm.cp_pbpar; | ||
63 | break; | ||
64 | |||
65 | case fsiop_portc: | ||
66 | dir = &im->im_ioport.iop_pcdir; | ||
67 | dat = &im->im_ioport.iop_pcdat; | ||
68 | ppar = &im->im_ioport.iop_pcpar; | ||
69 | break; | ||
70 | |||
71 | case fsiop_portd: | ||
72 | dir = &im->im_ioport.iop_pddir; | ||
73 | dat = &im->im_ioport.iop_pddat; | ||
74 | ppar = &im->im_ioport.iop_pdpar; | ||
75 | break; | ||
76 | |||
77 | case fsiop_porte: | ||
78 | dir = &im->im_cpm.cp_pedir; | ||
79 | dat = &im->im_cpm.cp_pedat; | ||
80 | ppar = &im->im_cpm.cp_pepar; | ||
81 | break; | ||
82 | |||
83 | default: | ||
84 | printk(KERN_ERR DRV_MODULE_NAME | ||
85 | "Illegal port value %d!\n", port); | ||
86 | return -EINVAL; | ||
87 | } | ||
88 | |||
89 | adv = bit >> 3; | ||
90 | dir = (char *)dir + adv; | ||
91 | dat = (char *)dat + adv; | ||
92 | ppar = (char *)ppar + adv; | ||
93 | |||
94 | msk = 1 << (7 - (bit & 7)); | ||
95 | if ((in_8(ppar) & msk) != 0) { | ||
96 | printk(KERN_ERR DRV_MODULE_NAME | ||
97 | "pin %d on port %d is not general purpose!\n", bit, port); | ||
98 | return -EINVAL; | ||
99 | } | ||
100 | |||
101 | *dirp = dir; | ||
102 | *datp = dat; | ||
103 | *mskp = msk; | ||
104 | |||
105 | return 0; | ||
106 | } | ||
107 | #endif | ||
108 | |||
109 | #ifdef CONFIG_8260 | ||
110 | static int bitbang_prep_bit(u8 **dirp, u8 **datp, u8 *mskp, int port, int bit) | ||
111 | { | ||
112 | iop_cpm2_t *io = &((cpm2_map_t *)fs_enet_immap)->im_ioport; | ||
113 | void *dir, *dat, *ppar; | ||
114 | int adv; | ||
115 | u8 msk; | ||
116 | |||
117 | switch (port) { | ||
118 | case fsiop_porta: | ||
119 | dir = &io->iop_pdira; | ||
120 | dat = &io->iop_pdata; | ||
121 | ppar = &io->iop_ppara; | ||
122 | break; | ||
123 | |||
124 | case fsiop_portb: | ||
125 | dir = &io->iop_pdirb; | ||
126 | dat = &io->iop_pdatb; | ||
127 | ppar = &io->iop_pparb; | ||
128 | break; | ||
129 | |||
130 | case fsiop_portc: | ||
131 | dir = &io->iop_pdirc; | ||
132 | dat = &io->iop_pdatc; | ||
133 | ppar = &io->iop_pparc; | ||
134 | break; | ||
135 | |||
136 | case fsiop_portd: | ||
137 | dir = &io->iop_pdird; | ||
138 | dat = &io->iop_pdatd; | ||
139 | ppar = &io->iop_ppard; | ||
140 | break; | ||
141 | |||
142 | default: | ||
143 | printk(KERN_ERR DRV_MODULE_NAME | ||
144 | "Illegal port value %d!\n", port); | ||
145 | return -EINVAL; | ||
146 | } | ||
147 | |||
148 | adv = bit >> 3; | ||
149 | dir = (char *)dir + adv; | ||
150 | dat = (char *)dat + adv; | ||
151 | ppar = (char *)ppar + adv; | ||
152 | |||
153 | msk = 1 << (7 - (bit & 7)); | ||
154 | if ((in_8(ppar) & msk) != 0) { | ||
155 | printk(KERN_ERR DRV_MODULE_NAME | ||
156 | "pin %d on port %d is not general purpose!\n", bit, port); | ||
157 | return -EINVAL; | ||
158 | } | ||
159 | |||
160 | *dirp = dir; | ||
161 | *datp = dat; | ||
162 | *mskp = msk; | ||
163 | |||
164 | return 0; | ||
165 | } | ||
166 | #endif | ||
167 | |||
168 | static inline void bb_set(u8 *p, u8 m) | ||
169 | { | ||
170 | out_8(p, in_8(p) | m); | ||
171 | } | ||
172 | |||
173 | static inline void bb_clr(u8 *p, u8 m) | ||
174 | { | ||
175 | out_8(p, in_8(p) & ~m); | ||
176 | } | ||
177 | |||
178 | static inline int bb_read(u8 *p, u8 m) | ||
179 | { | ||
180 | return (in_8(p) & m) != 0; | ||
181 | } | ||
182 | |||
183 | static inline void mdio_active(struct fs_enet_mii_bus *bus) | ||
184 | { | ||
185 | bb_set(bus->bitbang.mdio_dir, bus->bitbang.mdio_msk); | ||
186 | } | ||
187 | |||
188 | static inline void mdio_tristate(struct fs_enet_mii_bus *bus) | ||
189 | { | ||
190 | bb_clr(bus->bitbang.mdio_dir, bus->bitbang.mdio_msk); | ||
191 | } | ||
192 | |||
193 | static inline int mdio_read(struct fs_enet_mii_bus *bus) | ||
194 | { | ||
195 | return bb_read(bus->bitbang.mdio_dat, bus->bitbang.mdio_msk); | ||
196 | } | ||
197 | |||
198 | static inline void mdio(struct fs_enet_mii_bus *bus, int what) | ||
199 | { | ||
200 | if (what) | ||
201 | bb_set(bus->bitbang.mdio_dat, bus->bitbang.mdio_msk); | ||
202 | else | ||
203 | bb_clr(bus->bitbang.mdio_dat, bus->bitbang.mdio_msk); | ||
204 | } | ||
205 | |||
206 | static inline void mdc(struct fs_enet_mii_bus *bus, int what) | ||
207 | { | ||
208 | if (what) | ||
209 | bb_set(bus->bitbang.mdc_dat, bus->bitbang.mdc_msk); | ||
210 | else | ||
211 | bb_clr(bus->bitbang.mdc_dat, bus->bitbang.mdc_msk); | ||
212 | } | ||
213 | |||
214 | static inline void mii_delay(struct fs_enet_mii_bus *bus) | ||
215 | { | ||
216 | udelay(bus->bus_info->i.bitbang.delay); | ||
217 | } | ||
218 | |||
219 | /* Utility to send the preamble, address, and register (common to read and write). */ | ||
220 | static void bitbang_pre(struct fs_enet_mii_bus *bus, int read, u8 addr, u8 reg) | ||
221 | { | ||
222 | int j; | ||
223 | |||
224 | /* | ||
225 | * Send a 32 bit preamble ('1's) with an extra '1' bit for good measure. | ||
226 | * The IEEE spec says this is a PHY optional requirement. The AMD | ||
227 | * 79C874 requires one after power up and one after a MII communications | ||
228 | * error. This means that we are doing more preambles than we need, | ||
229 | * but it is safer and will be much more robust. | ||
230 | */ | ||
231 | |||
232 | mdio_active(bus); | ||
233 | mdio(bus, 1); | ||
234 | for (j = 0; j < 32; j++) { | ||
235 | mdc(bus, 0); | ||
236 | mii_delay(bus); | ||
237 | mdc(bus, 1); | ||
238 | mii_delay(bus); | ||
239 | } | ||
240 | |||
241 | /* send the start bit (01) and the read opcode (10) or write (10) */ | ||
242 | mdc(bus, 0); | ||
243 | mdio(bus, 0); | ||
244 | mii_delay(bus); | ||
245 | mdc(bus, 1); | ||
246 | mii_delay(bus); | ||
247 | mdc(bus, 0); | ||
248 | mdio(bus, 1); | ||
249 | mii_delay(bus); | ||
250 | mdc(bus, 1); | ||
251 | mii_delay(bus); | ||
252 | mdc(bus, 0); | ||
253 | mdio(bus, read); | ||
254 | mii_delay(bus); | ||
255 | mdc(bus, 1); | ||
256 | mii_delay(bus); | ||
257 | mdc(bus, 0); | ||
258 | mdio(bus, !read); | ||
259 | mii_delay(bus); | ||
260 | mdc(bus, 1); | ||
261 | mii_delay(bus); | ||
262 | |||
263 | /* send the PHY address */ | ||
264 | for (j = 0; j < 5; j++) { | ||
265 | mdc(bus, 0); | ||
266 | mdio(bus, (addr & 0x10) != 0); | ||
267 | mii_delay(bus); | ||
268 | mdc(bus, 1); | ||
269 | mii_delay(bus); | ||
270 | addr <<= 1; | ||
271 | } | ||
272 | |||
273 | /* send the register address */ | ||
274 | for (j = 0; j < 5; j++) { | ||
275 | mdc(bus, 0); | ||
276 | mdio(bus, (reg & 0x10) != 0); | ||
277 | mii_delay(bus); | ||
278 | mdc(bus, 1); | ||
279 | mii_delay(bus); | ||
280 | reg <<= 1; | ||
281 | } | ||
282 | } | ||
283 | |||
284 | static int mii_read(struct fs_enet_mii_bus *bus, int phy_id, int location) | ||
285 | { | ||
286 | u16 rdreg; | ||
287 | int ret, j; | ||
288 | u8 addr = phy_id & 0xff; | ||
289 | u8 reg = location & 0xff; | ||
290 | |||
291 | bitbang_pre(bus, 1, addr, reg); | ||
292 | |||
293 | /* tri-state our MDIO I/O pin so we can read */ | ||
294 | mdc(bus, 0); | ||
295 | mdio_tristate(bus); | ||
296 | mii_delay(bus); | ||
297 | mdc(bus, 1); | ||
298 | mii_delay(bus); | ||
299 | |||
300 | /* check the turnaround bit: the PHY should be driving it to zero */ | ||
301 | if (mdio_read(bus) != 0) { | ||
302 | /* PHY didn't drive TA low */ | ||
303 | for (j = 0; j < 32; j++) { | ||
304 | mdc(bus, 0); | ||
305 | mii_delay(bus); | ||
306 | mdc(bus, 1); | ||
307 | mii_delay(bus); | ||
308 | } | ||
309 | ret = -1; | ||
310 | goto out; | ||
311 | } | ||
312 | |||
313 | mdc(bus, 0); | ||
314 | mii_delay(bus); | ||
315 | |||
316 | /* read 16 bits of register data, MSB first */ | ||
317 | rdreg = 0; | ||
318 | for (j = 0; j < 16; j++) { | ||
319 | mdc(bus, 1); | ||
320 | mii_delay(bus); | ||
321 | rdreg <<= 1; | ||
322 | rdreg |= mdio_read(bus); | ||
323 | mdc(bus, 0); | ||
324 | mii_delay(bus); | ||
325 | } | ||
326 | |||
327 | mdc(bus, 1); | ||
328 | mii_delay(bus); | ||
329 | mdc(bus, 0); | ||
330 | mii_delay(bus); | ||
331 | mdc(bus, 1); | ||
332 | mii_delay(bus); | ||
333 | |||
334 | ret = rdreg; | ||
335 | out: | ||
336 | return ret; | ||
337 | } | ||
338 | |||
339 | static void mii_write(struct fs_enet_mii_bus *bus, int phy_id, int location, int val) | ||
340 | { | ||
341 | int j; | ||
342 | u8 addr = phy_id & 0xff; | ||
343 | u8 reg = location & 0xff; | ||
344 | u16 value = val & 0xffff; | ||
345 | |||
346 | bitbang_pre(bus, 0, addr, reg); | ||
347 | |||
348 | /* send the turnaround (10) */ | ||
349 | mdc(bus, 0); | ||
350 | mdio(bus, 1); | ||
351 | mii_delay(bus); | ||
352 | mdc(bus, 1); | ||
353 | mii_delay(bus); | ||
354 | mdc(bus, 0); | ||
355 | mdio(bus, 0); | ||
356 | mii_delay(bus); | ||
357 | mdc(bus, 1); | ||
358 | mii_delay(bus); | ||
359 | |||
360 | /* write 16 bits of register data, MSB first */ | ||
361 | for (j = 0; j < 16; j++) { | ||
362 | mdc(bus, 0); | ||
363 | mdio(bus, (value & 0x8000) != 0); | ||
364 | mii_delay(bus); | ||
365 | mdc(bus, 1); | ||
366 | mii_delay(bus); | ||
367 | value <<= 1; | ||
368 | } | ||
369 | |||
370 | /* | ||
371 | * Tri-state the MDIO line. | ||
372 | */ | ||
373 | mdio_tristate(bus); | ||
374 | mdc(bus, 0); | ||
375 | mii_delay(bus); | ||
376 | mdc(bus, 1); | ||
377 | mii_delay(bus); | ||
378 | } | ||
379 | |||
380 | int fs_mii_bitbang_init(struct fs_enet_mii_bus *bus) | ||
381 | { | ||
382 | const struct fs_mii_bus_info *bi = bus->bus_info; | ||
383 | int r; | ||
384 | |||
385 | r = bitbang_prep_bit(&bus->bitbang.mdio_dir, | ||
386 | &bus->bitbang.mdio_dat, | ||
387 | &bus->bitbang.mdio_msk, | ||
388 | bi->i.bitbang.mdio_port, | ||
389 | bi->i.bitbang.mdio_bit); | ||
390 | if (r != 0) | ||
391 | return r; | ||
392 | |||
393 | r = bitbang_prep_bit(&bus->bitbang.mdc_dir, | ||
394 | &bus->bitbang.mdc_dat, | ||
395 | &bus->bitbang.mdc_msk, | ||
396 | bi->i.bitbang.mdc_port, | ||
397 | bi->i.bitbang.mdc_bit); | ||
398 | if (r != 0) | ||
399 | return r; | ||
400 | |||
401 | bus->mii_read = mii_read; | ||
402 | bus->mii_write = mii_write; | ||
403 | |||
404 | return 0; | ||
405 | } | ||
diff --git a/drivers/net/fs_enet/mii-fixed.c b/drivers/net/fs_enet/mii-fixed.c new file mode 100644 index 000000000000..b3e192d612e5 --- /dev/null +++ b/drivers/net/fs_enet/mii-fixed.c | |||
@@ -0,0 +1,92 @@ | |||
1 | /* | ||
2 | * Combined Ethernet driver for Motorola MPC8xx and MPC82xx. | ||
3 | * | ||
4 | * Copyright (c) 2003 Intracom S.A. | ||
5 | * by Pantelis Antoniou <panto@intracom.gr> | ||
6 | * | ||
7 | * 2005 (c) MontaVista Software, Inc. | ||
8 | * Vitaly Bordug <vbordug@ru.mvista.com> | ||
9 | * | ||
10 | * This file is licensed under the terms of the GNU General Public License | ||
11 | * version 2. This program is licensed "as is" without any warranty of any | ||
12 | * kind, whether express or implied. | ||
13 | */ | ||
14 | |||
15 | |||
16 | #include <linux/config.h> | ||
17 | #include <linux/module.h> | ||
18 | #include <linux/types.h> | ||
19 | #include <linux/kernel.h> | ||
20 | #include <linux/sched.h> | ||
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> | ||
27 | #include <linux/pci.h> | ||
28 | #include <linux/init.h> | ||
29 | #include <linux/delay.h> | ||
30 | #include <linux/netdevice.h> | ||
31 | #include <linux/etherdevice.h> | ||
32 | #include <linux/skbuff.h> | ||
33 | #include <linux/spinlock.h> | ||
34 | #include <linux/mii.h> | ||
35 | #include <linux/ethtool.h> | ||
36 | #include <linux/bitops.h> | ||
37 | |||
38 | #include <asm/pgtable.h> | ||
39 | #include <asm/irq.h> | ||
40 | #include <asm/uaccess.h> | ||
41 | |||
42 | #include "fs_enet.h" | ||
43 | |||
44 | static const u16 mii_regs[7] = { | ||
45 | 0x3100, | ||
46 | 0x786d, | ||
47 | 0x0fff, | ||
48 | 0x0fff, | ||
49 | 0x01e1, | ||
50 | 0x45e1, | ||
51 | 0x0003, | ||
52 | }; | ||
53 | |||
54 | static int mii_read(struct fs_enet_mii_bus *bus, int phy_id, int location) | ||
55 | { | ||
56 | int ret = 0; | ||
57 | |||
58 | if ((unsigned int)location >= ARRAY_SIZE(mii_regs)) | ||
59 | return -1; | ||
60 | |||
61 | if (location != 5) | ||
62 | ret = mii_regs[location]; | ||
63 | else | ||
64 | ret = bus->fixed.lpa; | ||
65 | |||
66 | return ret; | ||
67 | } | ||
68 | |||
69 | static void mii_write(struct fs_enet_mii_bus *bus, int phy_id, int location, int val) | ||
70 | { | ||
71 | /* do nothing */ | ||
72 | } | ||
73 | |||
74 | int fs_mii_fixed_init(struct fs_enet_mii_bus *bus) | ||
75 | { | ||
76 | const struct fs_mii_bus_info *bi = bus->bus_info; | ||
77 | |||
78 | bus->fixed.lpa = 0x45e1; /* default 100Mb, full duplex */ | ||
79 | |||
80 | /* if speed is fixed at 10Mb, remove 100Mb modes */ | ||
81 | if (bi->i.fixed.speed == 10) | ||
82 | bus->fixed.lpa &= ~LPA_100; | ||
83 | |||
84 | /* if duplex is half, remove full duplex modes */ | ||
85 | if (bi->i.fixed.duplex == 0) | ||
86 | bus->fixed.lpa &= ~LPA_DUPLEX; | ||
87 | |||
88 | bus->mii_read = mii_read; | ||
89 | bus->mii_write = mii_write; | ||
90 | |||
91 | return 0; | ||
92 | } | ||