diff options
Diffstat (limited to 'drivers/net/fs_enet')
-rw-r--r-- | drivers/net/fs_enet/Kconfig | 34 | ||||
-rw-r--r-- | drivers/net/fs_enet/Makefile | 14 | ||||
-rw-r--r-- | drivers/net/fs_enet/fec.h | 42 | ||||
-rw-r--r-- | drivers/net/fs_enet/fs_enet-main.c | 1196 | ||||
-rw-r--r-- | drivers/net/fs_enet/fs_enet.h | 244 | ||||
-rw-r--r-- | drivers/net/fs_enet/mac-fcc.c | 584 | ||||
-rw-r--r-- | drivers/net/fs_enet/mac-fec.c | 498 | ||||
-rw-r--r-- | drivers/net/fs_enet/mac-scc.c | 484 | ||||
-rw-r--r-- | drivers/net/fs_enet/mii-bitbang.c | 246 | ||||
-rw-r--r-- | drivers/net/fs_enet/mii-fec.c | 251 |
10 files changed, 3593 insertions, 0 deletions
diff --git a/drivers/net/fs_enet/Kconfig b/drivers/net/fs_enet/Kconfig new file mode 100644 index 00000000000..fc073b5a38c --- /dev/null +++ b/drivers/net/fs_enet/Kconfig | |||
@@ -0,0 +1,34 @@ | |||
1 | config FS_ENET | ||
2 | tristate "Freescale Ethernet Driver" | ||
3 | depends on CPM1 || CPM2 || PPC_MPC512x | ||
4 | select MII | ||
5 | select PHYLIB | ||
6 | |||
7 | config FS_ENET_MPC5121_FEC | ||
8 | def_bool y if (FS_ENET && PPC_MPC512x) | ||
9 | select FS_ENET_HAS_FEC | ||
10 | |||
11 | config FS_ENET_HAS_SCC | ||
12 | bool "Chip has an SCC usable for ethernet" | ||
13 | depends on FS_ENET && (CPM1 || CPM2) | ||
14 | default y | ||
15 | |||
16 | config FS_ENET_HAS_FCC | ||
17 | bool "Chip has an FCC usable for ethernet" | ||
18 | depends on FS_ENET && CPM2 | ||
19 | default y | ||
20 | |||
21 | config FS_ENET_HAS_FEC | ||
22 | bool "Chip has an FEC usable for ethernet" | ||
23 | depends on FS_ENET && (CPM1 || FS_ENET_MPC5121_FEC) | ||
24 | select FS_ENET_MDIO_FEC | ||
25 | default y | ||
26 | |||
27 | config FS_ENET_MDIO_FEC | ||
28 | tristate "MDIO driver for FEC" | ||
29 | depends on FS_ENET && (CPM1 || FS_ENET_MPC5121_FEC) | ||
30 | |||
31 | config FS_ENET_MDIO_FCC | ||
32 | tristate "MDIO driver for FCC" | ||
33 | depends on FS_ENET && CPM2 | ||
34 | select MDIO_BITBANG | ||
diff --git a/drivers/net/fs_enet/Makefile b/drivers/net/fs_enet/Makefile new file mode 100644 index 00000000000..d4a305ee345 --- /dev/null +++ b/drivers/net/fs_enet/Makefile | |||
@@ -0,0 +1,14 @@ | |||
1 | # | ||
2 | # Makefile for the Freescale Ethernet controllers | ||
3 | # | ||
4 | |||
5 | obj-$(CONFIG_FS_ENET) += fs_enet.o | ||
6 | |||
7 | fs_enet-$(CONFIG_FS_ENET_HAS_SCC) += mac-scc.o | ||
8 | fs_enet-$(CONFIG_FS_ENET_HAS_FEC) += mac-fec.o | ||
9 | fs_enet-$(CONFIG_FS_ENET_HAS_FCC) += mac-fcc.o | ||
10 | |||
11 | obj-$(CONFIG_FS_ENET_MDIO_FEC) += mii-fec.o | ||
12 | obj-$(CONFIG_FS_ENET_MDIO_FCC) += mii-bitbang.o | ||
13 | |||
14 | fs_enet-objs := fs_enet-main.o $(fs_enet-m) | ||
diff --git a/drivers/net/fs_enet/fec.h b/drivers/net/fs_enet/fec.h new file mode 100644 index 00000000000..e980527e2b9 --- /dev/null +++ b/drivers/net/fs_enet/fec.h | |||
@@ -0,0 +1,42 @@ | |||
1 | #ifndef FS_ENET_FEC_H | ||
2 | #define FS_ENET_FEC_H | ||
3 | |||
4 | /* CRC polynomium used by the FEC for the multicast group filtering */ | ||
5 | #define FEC_CRC_POLY 0x04C11DB7 | ||
6 | |||
7 | #define FEC_MAX_MULTICAST_ADDRS 64 | ||
8 | |||
9 | /* Interrupt events/masks. | ||
10 | */ | ||
11 | #define FEC_ENET_HBERR 0x80000000U /* Heartbeat error */ | ||
12 | #define FEC_ENET_BABR 0x40000000U /* Babbling receiver */ | ||
13 | #define FEC_ENET_BABT 0x20000000U /* Babbling transmitter */ | ||
14 | #define FEC_ENET_GRA 0x10000000U /* Graceful stop complete */ | ||
15 | #define FEC_ENET_TXF 0x08000000U /* Full frame transmitted */ | ||
16 | #define FEC_ENET_TXB 0x04000000U /* A buffer was transmitted */ | ||
17 | #define FEC_ENET_RXF 0x02000000U /* Full frame received */ | ||
18 | #define FEC_ENET_RXB 0x01000000U /* A buffer was received */ | ||
19 | #define FEC_ENET_MII 0x00800000U /* MII interrupt */ | ||
20 | #define FEC_ENET_EBERR 0x00400000U /* SDMA bus error */ | ||
21 | |||
22 | #define FEC_ECNTRL_PINMUX 0x00000004 | ||
23 | #define FEC_ECNTRL_ETHER_EN 0x00000002 | ||
24 | #define FEC_ECNTRL_RESET 0x00000001 | ||
25 | |||
26 | #define FEC_RCNTRL_BC_REJ 0x00000010 | ||
27 | #define FEC_RCNTRL_PROM 0x00000008 | ||
28 | #define FEC_RCNTRL_MII_MODE 0x00000004 | ||
29 | #define FEC_RCNTRL_DRT 0x00000002 | ||
30 | #define FEC_RCNTRL_LOOP 0x00000001 | ||
31 | |||
32 | #define FEC_TCNTRL_FDEN 0x00000004 | ||
33 | #define FEC_TCNTRL_HBC 0x00000002 | ||
34 | #define FEC_TCNTRL_GTS 0x00000001 | ||
35 | |||
36 | |||
37 | |||
38 | /* | ||
39 | * Delay to wait for FEC reset command to complete (in us) | ||
40 | */ | ||
41 | #define FEC_RESET_DELAY 50 | ||
42 | #endif | ||
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 00000000000..329ef231a09 --- /dev/null +++ b/drivers/net/fs_enet/fs_enet-main.c | |||
@@ -0,0 +1,1196 @@ | |||
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/module.h> | ||
19 | #include <linux/kernel.h> | ||
20 | #include <linux/types.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/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 | #include <linux/platform_device.h> | ||
38 | #include <linux/phy.h> | ||
39 | #include <linux/of.h> | ||
40 | #include <linux/of_mdio.h> | ||
41 | #include <linux/of_platform.h> | ||
42 | #include <linux/of_gpio.h> | ||
43 | #include <linux/of_net.h> | ||
44 | |||
45 | #include <linux/vmalloc.h> | ||
46 | #include <asm/pgtable.h> | ||
47 | #include <asm/irq.h> | ||
48 | #include <asm/uaccess.h> | ||
49 | |||
50 | #include "fs_enet.h" | ||
51 | |||
52 | /*************************************************/ | ||
53 | |||
54 | MODULE_AUTHOR("Pantelis Antoniou <panto@intracom.gr>"); | ||
55 | MODULE_DESCRIPTION("Freescale Ethernet Driver"); | ||
56 | MODULE_LICENSE("GPL"); | ||
57 | MODULE_VERSION(DRV_MODULE_VERSION); | ||
58 | |||
59 | static int fs_enet_debug = -1; /* -1 == use FS_ENET_DEF_MSG_ENABLE as value */ | ||
60 | module_param(fs_enet_debug, int, 0); | ||
61 | MODULE_PARM_DESC(fs_enet_debug, | ||
62 | "Freescale bitmapped debugging message enable value"); | ||
63 | |||
64 | #ifdef CONFIG_NET_POLL_CONTROLLER | ||
65 | static void fs_enet_netpoll(struct net_device *dev); | ||
66 | #endif | ||
67 | |||
68 | static void fs_set_multicast_list(struct net_device *dev) | ||
69 | { | ||
70 | struct fs_enet_private *fep = netdev_priv(dev); | ||
71 | |||
72 | (*fep->ops->set_multicast_list)(dev); | ||
73 | } | ||
74 | |||
75 | static void skb_align(struct sk_buff *skb, int align) | ||
76 | { | ||
77 | int off = ((unsigned long)skb->data) & (align - 1); | ||
78 | |||
79 | if (off) | ||
80 | skb_reserve(skb, align - off); | ||
81 | } | ||
82 | |||
83 | /* NAPI receive function */ | ||
84 | static int fs_enet_rx_napi(struct napi_struct *napi, int budget) | ||
85 | { | ||
86 | struct fs_enet_private *fep = container_of(napi, struct fs_enet_private, napi); | ||
87 | struct net_device *dev = fep->ndev; | ||
88 | const struct fs_platform_info *fpi = fep->fpi; | ||
89 | cbd_t __iomem *bdp; | ||
90 | struct sk_buff *skb, *skbn, *skbt; | ||
91 | int received = 0; | ||
92 | u16 pkt_len, sc; | ||
93 | int curidx; | ||
94 | |||
95 | /* | ||
96 | * First, grab all of the stats for the incoming packet. | ||
97 | * These get messed up if we get called due to a busy condition. | ||
98 | */ | ||
99 | bdp = fep->cur_rx; | ||
100 | |||
101 | /* clear RX status bits for napi*/ | ||
102 | (*fep->ops->napi_clear_rx_event)(dev); | ||
103 | |||
104 | while (((sc = CBDR_SC(bdp)) & BD_ENET_RX_EMPTY) == 0) { | ||
105 | curidx = bdp - fep->rx_bd_base; | ||
106 | |||
107 | /* | ||
108 | * Since we have allocated space to hold a complete frame, | ||
109 | * the last indicator should be set. | ||
110 | */ | ||
111 | if ((sc & BD_ENET_RX_LAST) == 0) | ||
112 | dev_warn(fep->dev, "rcv is not +last\n"); | ||
113 | |||
114 | /* | ||
115 | * Check for errors. | ||
116 | */ | ||
117 | if (sc & (BD_ENET_RX_LG | BD_ENET_RX_SH | BD_ENET_RX_CL | | ||
118 | BD_ENET_RX_NO | BD_ENET_RX_CR | BD_ENET_RX_OV)) { | ||
119 | fep->stats.rx_errors++; | ||
120 | /* Frame too long or too short. */ | ||
121 | if (sc & (BD_ENET_RX_LG | BD_ENET_RX_SH)) | ||
122 | fep->stats.rx_length_errors++; | ||
123 | /* Frame alignment */ | ||
124 | if (sc & (BD_ENET_RX_NO | BD_ENET_RX_CL)) | ||
125 | fep->stats.rx_frame_errors++; | ||
126 | /* CRC Error */ | ||
127 | if (sc & BD_ENET_RX_CR) | ||
128 | fep->stats.rx_crc_errors++; | ||
129 | /* FIFO overrun */ | ||
130 | if (sc & BD_ENET_RX_OV) | ||
131 | fep->stats.rx_crc_errors++; | ||
132 | |||
133 | skb = fep->rx_skbuff[curidx]; | ||
134 | |||
135 | dma_unmap_single(fep->dev, CBDR_BUFADDR(bdp), | ||
136 | L1_CACHE_ALIGN(PKT_MAXBUF_SIZE), | ||
137 | DMA_FROM_DEVICE); | ||
138 | |||
139 | skbn = skb; | ||
140 | |||
141 | } else { | ||
142 | skb = fep->rx_skbuff[curidx]; | ||
143 | |||
144 | dma_unmap_single(fep->dev, CBDR_BUFADDR(bdp), | ||
145 | L1_CACHE_ALIGN(PKT_MAXBUF_SIZE), | ||
146 | DMA_FROM_DEVICE); | ||
147 | |||
148 | /* | ||
149 | * Process the incoming frame. | ||
150 | */ | ||
151 | fep->stats.rx_packets++; | ||
152 | pkt_len = CBDR_DATLEN(bdp) - 4; /* remove CRC */ | ||
153 | fep->stats.rx_bytes += pkt_len + 4; | ||
154 | |||
155 | if (pkt_len <= fpi->rx_copybreak) { | ||
156 | /* +2 to make IP header L1 cache aligned */ | ||
157 | skbn = dev_alloc_skb(pkt_len + 2); | ||
158 | if (skbn != NULL) { | ||
159 | skb_reserve(skbn, 2); /* align IP header */ | ||
160 | skb_copy_from_linear_data(skb, | ||
161 | skbn->data, pkt_len); | ||
162 | /* swap */ | ||
163 | skbt = skb; | ||
164 | skb = skbn; | ||
165 | skbn = skbt; | ||
166 | } | ||
167 | } else { | ||
168 | skbn = dev_alloc_skb(ENET_RX_FRSIZE); | ||
169 | |||
170 | if (skbn) | ||
171 | skb_align(skbn, ENET_RX_ALIGN); | ||
172 | } | ||
173 | |||
174 | if (skbn != NULL) { | ||
175 | skb_put(skb, pkt_len); /* Make room */ | ||
176 | skb->protocol = eth_type_trans(skb, dev); | ||
177 | received++; | ||
178 | netif_receive_skb(skb); | ||
179 | } else { | ||
180 | dev_warn(fep->dev, | ||
181 | "Memory squeeze, dropping packet.\n"); | ||
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 | if (received >= budget) | ||
205 | break; | ||
206 | } | ||
207 | |||
208 | fep->cur_rx = bdp; | ||
209 | |||
210 | if (received < budget) { | ||
211 | /* done */ | ||
212 | napi_complete(napi); | ||
213 | (*fep->ops->napi_enable_rx)(dev); | ||
214 | } | ||
215 | return received; | ||
216 | } | ||
217 | |||
218 | /* non NAPI receive function */ | ||
219 | static int fs_enet_rx_non_napi(struct net_device *dev) | ||
220 | { | ||
221 | struct fs_enet_private *fep = netdev_priv(dev); | ||
222 | const struct fs_platform_info *fpi = fep->fpi; | ||
223 | cbd_t __iomem *bdp; | ||
224 | struct sk_buff *skb, *skbn, *skbt; | ||
225 | int received = 0; | ||
226 | u16 pkt_len, sc; | ||
227 | int curidx; | ||
228 | /* | ||
229 | * First, grab all of the stats for the incoming packet. | ||
230 | * These get messed up if we get called due to a busy condition. | ||
231 | */ | ||
232 | bdp = fep->cur_rx; | ||
233 | |||
234 | while (((sc = CBDR_SC(bdp)) & BD_ENET_RX_EMPTY) == 0) { | ||
235 | |||
236 | curidx = bdp - fep->rx_bd_base; | ||
237 | |||
238 | /* | ||
239 | * Since we have allocated space to hold a complete frame, | ||
240 | * the last indicator should be set. | ||
241 | */ | ||
242 | if ((sc & BD_ENET_RX_LAST) == 0) | ||
243 | dev_warn(fep->dev, "rcv is not +last\n"); | ||
244 | |||
245 | /* | ||
246 | * Check for errors. | ||
247 | */ | ||
248 | if (sc & (BD_ENET_RX_LG | BD_ENET_RX_SH | BD_ENET_RX_CL | | ||
249 | BD_ENET_RX_NO | BD_ENET_RX_CR | BD_ENET_RX_OV)) { | ||
250 | fep->stats.rx_errors++; | ||
251 | /* Frame too long or too short. */ | ||
252 | if (sc & (BD_ENET_RX_LG | BD_ENET_RX_SH)) | ||
253 | fep->stats.rx_length_errors++; | ||
254 | /* Frame alignment */ | ||
255 | if (sc & (BD_ENET_RX_NO | BD_ENET_RX_CL)) | ||
256 | fep->stats.rx_frame_errors++; | ||
257 | /* CRC Error */ | ||
258 | if (sc & BD_ENET_RX_CR) | ||
259 | fep->stats.rx_crc_errors++; | ||
260 | /* FIFO overrun */ | ||
261 | if (sc & BD_ENET_RX_OV) | ||
262 | fep->stats.rx_crc_errors++; | ||
263 | |||
264 | skb = fep->rx_skbuff[curidx]; | ||
265 | |||
266 | dma_unmap_single(fep->dev, CBDR_BUFADDR(bdp), | ||
267 | L1_CACHE_ALIGN(PKT_MAXBUF_SIZE), | ||
268 | DMA_FROM_DEVICE); | ||
269 | |||
270 | skbn = skb; | ||
271 | |||
272 | } else { | ||
273 | |||
274 | skb = fep->rx_skbuff[curidx]; | ||
275 | |||
276 | dma_unmap_single(fep->dev, CBDR_BUFADDR(bdp), | ||
277 | L1_CACHE_ALIGN(PKT_MAXBUF_SIZE), | ||
278 | DMA_FROM_DEVICE); | ||
279 | |||
280 | /* | ||
281 | * Process the incoming frame. | ||
282 | */ | ||
283 | fep->stats.rx_packets++; | ||
284 | pkt_len = CBDR_DATLEN(bdp) - 4; /* remove CRC */ | ||
285 | fep->stats.rx_bytes += pkt_len + 4; | ||
286 | |||
287 | if (pkt_len <= fpi->rx_copybreak) { | ||
288 | /* +2 to make IP header L1 cache aligned */ | ||
289 | skbn = dev_alloc_skb(pkt_len + 2); | ||
290 | if (skbn != NULL) { | ||
291 | skb_reserve(skbn, 2); /* align IP header */ | ||
292 | skb_copy_from_linear_data(skb, | ||
293 | skbn->data, pkt_len); | ||
294 | /* swap */ | ||
295 | skbt = skb; | ||
296 | skb = skbn; | ||
297 | skbn = skbt; | ||
298 | } | ||
299 | } else { | ||
300 | skbn = dev_alloc_skb(ENET_RX_FRSIZE); | ||
301 | |||
302 | if (skbn) | ||
303 | skb_align(skbn, ENET_RX_ALIGN); | ||
304 | } | ||
305 | |||
306 | if (skbn != NULL) { | ||
307 | skb_put(skb, pkt_len); /* Make room */ | ||
308 | skb->protocol = eth_type_trans(skb, dev); | ||
309 | received++; | ||
310 | netif_rx(skb); | ||
311 | } else { | ||
312 | dev_warn(fep->dev, | ||
313 | "Memory squeeze, dropping packet.\n"); | ||
314 | fep->stats.rx_dropped++; | ||
315 | skbn = skb; | ||
316 | } | ||
317 | } | ||
318 | |||
319 | fep->rx_skbuff[curidx] = skbn; | ||
320 | CBDW_BUFADDR(bdp, dma_map_single(fep->dev, skbn->data, | ||
321 | L1_CACHE_ALIGN(PKT_MAXBUF_SIZE), | ||
322 | DMA_FROM_DEVICE)); | ||
323 | CBDW_DATLEN(bdp, 0); | ||
324 | CBDW_SC(bdp, (sc & ~BD_ENET_RX_STATS) | BD_ENET_RX_EMPTY); | ||
325 | |||
326 | /* | ||
327 | * Update BD pointer to next entry. | ||
328 | */ | ||
329 | if ((sc & BD_ENET_RX_WRAP) == 0) | ||
330 | bdp++; | ||
331 | else | ||
332 | bdp = fep->rx_bd_base; | ||
333 | |||
334 | (*fep->ops->rx_bd_done)(dev); | ||
335 | } | ||
336 | |||
337 | fep->cur_rx = bdp; | ||
338 | |||
339 | return 0; | ||
340 | } | ||
341 | |||
342 | static void fs_enet_tx(struct net_device *dev) | ||
343 | { | ||
344 | struct fs_enet_private *fep = netdev_priv(dev); | ||
345 | cbd_t __iomem *bdp; | ||
346 | struct sk_buff *skb; | ||
347 | int dirtyidx, do_wake, do_restart; | ||
348 | u16 sc; | ||
349 | |||
350 | spin_lock(&fep->tx_lock); | ||
351 | bdp = fep->dirty_tx; | ||
352 | |||
353 | do_wake = do_restart = 0; | ||
354 | while (((sc = CBDR_SC(bdp)) & BD_ENET_TX_READY) == 0) { | ||
355 | dirtyidx = bdp - fep->tx_bd_base; | ||
356 | |||
357 | if (fep->tx_free == fep->tx_ring) | ||
358 | break; | ||
359 | |||
360 | skb = fep->tx_skbuff[dirtyidx]; | ||
361 | |||
362 | /* | ||
363 | * Check for errors. | ||
364 | */ | ||
365 | if (sc & (BD_ENET_TX_HB | BD_ENET_TX_LC | | ||
366 | BD_ENET_TX_RL | BD_ENET_TX_UN | BD_ENET_TX_CSL)) { | ||
367 | |||
368 | if (sc & BD_ENET_TX_HB) /* No heartbeat */ | ||
369 | fep->stats.tx_heartbeat_errors++; | ||
370 | if (sc & BD_ENET_TX_LC) /* Late collision */ | ||
371 | fep->stats.tx_window_errors++; | ||
372 | if (sc & BD_ENET_TX_RL) /* Retrans limit */ | ||
373 | fep->stats.tx_aborted_errors++; | ||
374 | if (sc & BD_ENET_TX_UN) /* Underrun */ | ||
375 | fep->stats.tx_fifo_errors++; | ||
376 | if (sc & BD_ENET_TX_CSL) /* Carrier lost */ | ||
377 | fep->stats.tx_carrier_errors++; | ||
378 | |||
379 | if (sc & (BD_ENET_TX_LC | BD_ENET_TX_RL | BD_ENET_TX_UN)) { | ||
380 | fep->stats.tx_errors++; | ||
381 | do_restart = 1; | ||
382 | } | ||
383 | } else | ||
384 | fep->stats.tx_packets++; | ||
385 | |||
386 | if (sc & BD_ENET_TX_READY) { | ||
387 | dev_warn(fep->dev, | ||
388 | "HEY! Enet xmit interrupt and TX_READY.\n"); | ||
389 | } | ||
390 | |||
391 | /* | ||
392 | * Deferred means some collisions occurred during transmit, | ||
393 | * but we eventually sent the packet OK. | ||
394 | */ | ||
395 | if (sc & BD_ENET_TX_DEF) | ||
396 | fep->stats.collisions++; | ||
397 | |||
398 | /* unmap */ | ||
399 | dma_unmap_single(fep->dev, CBDR_BUFADDR(bdp), | ||
400 | skb->len, DMA_TO_DEVICE); | ||
401 | |||
402 | /* | ||
403 | * Free the sk buffer associated with this last transmit. | ||
404 | */ | ||
405 | dev_kfree_skb_irq(skb); | ||
406 | fep->tx_skbuff[dirtyidx] = NULL; | ||
407 | |||
408 | /* | ||
409 | * Update pointer to next buffer descriptor to be transmitted. | ||
410 | */ | ||
411 | if ((sc & BD_ENET_TX_WRAP) == 0) | ||
412 | bdp++; | ||
413 | else | ||
414 | bdp = fep->tx_bd_base; | ||
415 | |||
416 | /* | ||
417 | * Since we have freed up a buffer, the ring is no longer | ||
418 | * full. | ||
419 | */ | ||
420 | if (!fep->tx_free++) | ||
421 | do_wake = 1; | ||
422 | } | ||
423 | |||
424 | fep->dirty_tx = bdp; | ||
425 | |||
426 | if (do_restart) | ||
427 | (*fep->ops->tx_restart)(dev); | ||
428 | |||
429 | spin_unlock(&fep->tx_lock); | ||
430 | |||
431 | if (do_wake) | ||
432 | netif_wake_queue(dev); | ||
433 | } | ||
434 | |||
435 | /* | ||
436 | * The interrupt handler. | ||
437 | * This is called from the MPC core interrupt. | ||
438 | */ | ||
439 | static irqreturn_t | ||
440 | fs_enet_interrupt(int irq, void *dev_id) | ||
441 | { | ||
442 | struct net_device *dev = dev_id; | ||
443 | struct fs_enet_private *fep; | ||
444 | const struct fs_platform_info *fpi; | ||
445 | u32 int_events; | ||
446 | u32 int_clr_events; | ||
447 | int nr, napi_ok; | ||
448 | int handled; | ||
449 | |||
450 | fep = netdev_priv(dev); | ||
451 | fpi = fep->fpi; | ||
452 | |||
453 | nr = 0; | ||
454 | while ((int_events = (*fep->ops->get_int_events)(dev)) != 0) { | ||
455 | nr++; | ||
456 | |||
457 | int_clr_events = int_events; | ||
458 | if (fpi->use_napi) | ||
459 | int_clr_events &= ~fep->ev_napi_rx; | ||
460 | |||
461 | (*fep->ops->clear_int_events)(dev, int_clr_events); | ||
462 | |||
463 | if (int_events & fep->ev_err) | ||
464 | (*fep->ops->ev_error)(dev, int_events); | ||
465 | |||
466 | if (int_events & fep->ev_rx) { | ||
467 | if (!fpi->use_napi) | ||
468 | fs_enet_rx_non_napi(dev); | ||
469 | else { | ||
470 | napi_ok = napi_schedule_prep(&fep->napi); | ||
471 | |||
472 | (*fep->ops->napi_disable_rx)(dev); | ||
473 | (*fep->ops->clear_int_events)(dev, fep->ev_napi_rx); | ||
474 | |||
475 | /* NOTE: it is possible for FCCs in NAPI mode */ | ||
476 | /* to submit a spurious interrupt while in poll */ | ||
477 | if (napi_ok) | ||
478 | __napi_schedule(&fep->napi); | ||
479 | } | ||
480 | } | ||
481 | |||
482 | if (int_events & fep->ev_tx) | ||
483 | fs_enet_tx(dev); | ||
484 | } | ||
485 | |||
486 | handled = nr > 0; | ||
487 | return IRQ_RETVAL(handled); | ||
488 | } | ||
489 | |||
490 | void fs_init_bds(struct net_device *dev) | ||
491 | { | ||
492 | struct fs_enet_private *fep = netdev_priv(dev); | ||
493 | cbd_t __iomem *bdp; | ||
494 | struct sk_buff *skb; | ||
495 | int i; | ||
496 | |||
497 | fs_cleanup_bds(dev); | ||
498 | |||
499 | fep->dirty_tx = fep->cur_tx = fep->tx_bd_base; | ||
500 | fep->tx_free = fep->tx_ring; | ||
501 | fep->cur_rx = fep->rx_bd_base; | ||
502 | |||
503 | /* | ||
504 | * Initialize the receive buffer descriptors. | ||
505 | */ | ||
506 | for (i = 0, bdp = fep->rx_bd_base; i < fep->rx_ring; i++, bdp++) { | ||
507 | skb = dev_alloc_skb(ENET_RX_FRSIZE); | ||
508 | if (skb == NULL) { | ||
509 | dev_warn(fep->dev, | ||
510 | "Memory squeeze, unable to allocate skb\n"); | ||
511 | break; | ||
512 | } | ||
513 | skb_align(skb, ENET_RX_ALIGN); | ||
514 | fep->rx_skbuff[i] = skb; | ||
515 | CBDW_BUFADDR(bdp, | ||
516 | dma_map_single(fep->dev, skb->data, | ||
517 | L1_CACHE_ALIGN(PKT_MAXBUF_SIZE), | ||
518 | DMA_FROM_DEVICE)); | ||
519 | CBDW_DATLEN(bdp, 0); /* zero */ | ||
520 | CBDW_SC(bdp, BD_ENET_RX_EMPTY | | ||
521 | ((i < fep->rx_ring - 1) ? 0 : BD_SC_WRAP)); | ||
522 | } | ||
523 | /* | ||
524 | * if we failed, fillup remainder | ||
525 | */ | ||
526 | for (; i < fep->rx_ring; i++, bdp++) { | ||
527 | fep->rx_skbuff[i] = NULL; | ||
528 | CBDW_SC(bdp, (i < fep->rx_ring - 1) ? 0 : BD_SC_WRAP); | ||
529 | } | ||
530 | |||
531 | /* | ||
532 | * ...and the same for transmit. | ||
533 | */ | ||
534 | for (i = 0, bdp = fep->tx_bd_base; i < fep->tx_ring; i++, bdp++) { | ||
535 | fep->tx_skbuff[i] = NULL; | ||
536 | CBDW_BUFADDR(bdp, 0); | ||
537 | CBDW_DATLEN(bdp, 0); | ||
538 | CBDW_SC(bdp, (i < fep->tx_ring - 1) ? 0 : BD_SC_WRAP); | ||
539 | } | ||
540 | } | ||
541 | |||
542 | void fs_cleanup_bds(struct net_device *dev) | ||
543 | { | ||
544 | struct fs_enet_private *fep = netdev_priv(dev); | ||
545 | struct sk_buff *skb; | ||
546 | cbd_t __iomem *bdp; | ||
547 | int i; | ||
548 | |||
549 | /* | ||
550 | * Reset SKB transmit buffers. | ||
551 | */ | ||
552 | for (i = 0, bdp = fep->tx_bd_base; i < fep->tx_ring; i++, bdp++) { | ||
553 | if ((skb = fep->tx_skbuff[i]) == NULL) | ||
554 | continue; | ||
555 | |||
556 | /* unmap */ | ||
557 | dma_unmap_single(fep->dev, CBDR_BUFADDR(bdp), | ||
558 | skb->len, DMA_TO_DEVICE); | ||
559 | |||
560 | fep->tx_skbuff[i] = NULL; | ||
561 | dev_kfree_skb(skb); | ||
562 | } | ||
563 | |||
564 | /* | ||
565 | * Reset SKB receive buffers | ||
566 | */ | ||
567 | for (i = 0, bdp = fep->rx_bd_base; i < fep->rx_ring; i++, bdp++) { | ||
568 | if ((skb = fep->rx_skbuff[i]) == NULL) | ||
569 | continue; | ||
570 | |||
571 | /* unmap */ | ||
572 | dma_unmap_single(fep->dev, CBDR_BUFADDR(bdp), | ||
573 | L1_CACHE_ALIGN(PKT_MAXBUF_SIZE), | ||
574 | DMA_FROM_DEVICE); | ||
575 | |||
576 | fep->rx_skbuff[i] = NULL; | ||
577 | |||
578 | dev_kfree_skb(skb); | ||
579 | } | ||
580 | } | ||
581 | |||
582 | /**********************************************************************************/ | ||
583 | |||
584 | #ifdef CONFIG_FS_ENET_MPC5121_FEC | ||
585 | /* | ||
586 | * MPC5121 FEC requeries 4-byte alignment for TX data buffer! | ||
587 | */ | ||
588 | static struct sk_buff *tx_skb_align_workaround(struct net_device *dev, | ||
589 | struct sk_buff *skb) | ||
590 | { | ||
591 | struct sk_buff *new_skb; | ||
592 | struct fs_enet_private *fep = netdev_priv(dev); | ||
593 | |||
594 | /* Alloc new skb */ | ||
595 | new_skb = dev_alloc_skb(skb->len + 4); | ||
596 | if (!new_skb) { | ||
597 | if (net_ratelimit()) { | ||
598 | dev_warn(fep->dev, | ||
599 | "Memory squeeze, dropping tx packet.\n"); | ||
600 | } | ||
601 | return NULL; | ||
602 | } | ||
603 | |||
604 | /* Make sure new skb is properly aligned */ | ||
605 | skb_align(new_skb, 4); | ||
606 | |||
607 | /* Copy data to new skb ... */ | ||
608 | skb_copy_from_linear_data(skb, new_skb->data, skb->len); | ||
609 | skb_put(new_skb, skb->len); | ||
610 | |||
611 | /* ... and free an old one */ | ||
612 | dev_kfree_skb_any(skb); | ||
613 | |||
614 | return new_skb; | ||
615 | } | ||
616 | #endif | ||
617 | |||
618 | static int fs_enet_start_xmit(struct sk_buff *skb, struct net_device *dev) | ||
619 | { | ||
620 | struct fs_enet_private *fep = netdev_priv(dev); | ||
621 | cbd_t __iomem *bdp; | ||
622 | int curidx; | ||
623 | u16 sc; | ||
624 | unsigned long flags; | ||
625 | |||
626 | #ifdef CONFIG_FS_ENET_MPC5121_FEC | ||
627 | if (((unsigned long)skb->data) & 0x3) { | ||
628 | skb = tx_skb_align_workaround(dev, skb); | ||
629 | if (!skb) { | ||
630 | /* | ||
631 | * We have lost packet due to memory allocation error | ||
632 | * in tx_skb_align_workaround(). Hopefully original | ||
633 | * skb is still valid, so try transmit it later. | ||
634 | */ | ||
635 | return NETDEV_TX_BUSY; | ||
636 | } | ||
637 | } | ||
638 | #endif | ||
639 | spin_lock_irqsave(&fep->tx_lock, flags); | ||
640 | |||
641 | /* | ||
642 | * Fill in a Tx ring entry | ||
643 | */ | ||
644 | bdp = fep->cur_tx; | ||
645 | |||
646 | if (!fep->tx_free || (CBDR_SC(bdp) & BD_ENET_TX_READY)) { | ||
647 | netif_stop_queue(dev); | ||
648 | spin_unlock_irqrestore(&fep->tx_lock, flags); | ||
649 | |||
650 | /* | ||
651 | * Ooops. All transmit buffers are full. Bail out. | ||
652 | * This should not happen, since the tx queue should be stopped. | ||
653 | */ | ||
654 | dev_warn(fep->dev, "tx queue full!.\n"); | ||
655 | return NETDEV_TX_BUSY; | ||
656 | } | ||
657 | |||
658 | curidx = bdp - fep->tx_bd_base; | ||
659 | /* | ||
660 | * Clear all of the status flags. | ||
661 | */ | ||
662 | CBDC_SC(bdp, BD_ENET_TX_STATS); | ||
663 | |||
664 | /* | ||
665 | * Save skb pointer. | ||
666 | */ | ||
667 | fep->tx_skbuff[curidx] = skb; | ||
668 | |||
669 | fep->stats.tx_bytes += skb->len; | ||
670 | |||
671 | /* | ||
672 | * Push the data cache so the CPM does not get stale memory data. | ||
673 | */ | ||
674 | CBDW_BUFADDR(bdp, dma_map_single(fep->dev, | ||
675 | skb->data, skb->len, DMA_TO_DEVICE)); | ||
676 | CBDW_DATLEN(bdp, skb->len); | ||
677 | |||
678 | /* | ||
679 | * If this was the last BD in the ring, start at the beginning again. | ||
680 | */ | ||
681 | if ((CBDR_SC(bdp) & BD_ENET_TX_WRAP) == 0) | ||
682 | fep->cur_tx++; | ||
683 | else | ||
684 | fep->cur_tx = fep->tx_bd_base; | ||
685 | |||
686 | if (!--fep->tx_free) | ||
687 | netif_stop_queue(dev); | ||
688 | |||
689 | /* Trigger transmission start */ | ||
690 | sc = BD_ENET_TX_READY | BD_ENET_TX_INTR | | ||
691 | BD_ENET_TX_LAST | BD_ENET_TX_TC; | ||
692 | |||
693 | /* note that while FEC does not have this bit | ||
694 | * it marks it as available for software use | ||
695 | * yay for hw reuse :) */ | ||
696 | if (skb->len <= 60) | ||
697 | sc |= BD_ENET_TX_PAD; | ||
698 | CBDS_SC(bdp, sc); | ||
699 | |||
700 | skb_tx_timestamp(skb); | ||
701 | |||
702 | (*fep->ops->tx_kickstart)(dev); | ||
703 | |||
704 | spin_unlock_irqrestore(&fep->tx_lock, flags); | ||
705 | |||
706 | return NETDEV_TX_OK; | ||
707 | } | ||
708 | |||
709 | static void fs_timeout(struct net_device *dev) | ||
710 | { | ||
711 | struct fs_enet_private *fep = netdev_priv(dev); | ||
712 | unsigned long flags; | ||
713 | int wake = 0; | ||
714 | |||
715 | fep->stats.tx_errors++; | ||
716 | |||
717 | spin_lock_irqsave(&fep->lock, flags); | ||
718 | |||
719 | if (dev->flags & IFF_UP) { | ||
720 | phy_stop(fep->phydev); | ||
721 | (*fep->ops->stop)(dev); | ||
722 | (*fep->ops->restart)(dev); | ||
723 | phy_start(fep->phydev); | ||
724 | } | ||
725 | |||
726 | phy_start(fep->phydev); | ||
727 | wake = fep->tx_free && !(CBDR_SC(fep->cur_tx) & BD_ENET_TX_READY); | ||
728 | spin_unlock_irqrestore(&fep->lock, flags); | ||
729 | |||
730 | if (wake) | ||
731 | netif_wake_queue(dev); | ||
732 | } | ||
733 | |||
734 | /*----------------------------------------------------------------------------- | ||
735 | * generic link-change handler - should be sufficient for most cases | ||
736 | *-----------------------------------------------------------------------------*/ | ||
737 | static void generic_adjust_link(struct net_device *dev) | ||
738 | { | ||
739 | struct fs_enet_private *fep = netdev_priv(dev); | ||
740 | struct phy_device *phydev = fep->phydev; | ||
741 | int new_state = 0; | ||
742 | |||
743 | if (phydev->link) { | ||
744 | /* adjust to duplex mode */ | ||
745 | if (phydev->duplex != fep->oldduplex) { | ||
746 | new_state = 1; | ||
747 | fep->oldduplex = phydev->duplex; | ||
748 | } | ||
749 | |||
750 | if (phydev->speed != fep->oldspeed) { | ||
751 | new_state = 1; | ||
752 | fep->oldspeed = phydev->speed; | ||
753 | } | ||
754 | |||
755 | if (!fep->oldlink) { | ||
756 | new_state = 1; | ||
757 | fep->oldlink = 1; | ||
758 | } | ||
759 | |||
760 | if (new_state) | ||
761 | fep->ops->restart(dev); | ||
762 | } else if (fep->oldlink) { | ||
763 | new_state = 1; | ||
764 | fep->oldlink = 0; | ||
765 | fep->oldspeed = 0; | ||
766 | fep->oldduplex = -1; | ||
767 | } | ||
768 | |||
769 | if (new_state && netif_msg_link(fep)) | ||
770 | phy_print_status(phydev); | ||
771 | } | ||
772 | |||
773 | |||
774 | static void fs_adjust_link(struct net_device *dev) | ||
775 | { | ||
776 | struct fs_enet_private *fep = netdev_priv(dev); | ||
777 | unsigned long flags; | ||
778 | |||
779 | spin_lock_irqsave(&fep->lock, flags); | ||
780 | |||
781 | if(fep->ops->adjust_link) | ||
782 | fep->ops->adjust_link(dev); | ||
783 | else | ||
784 | generic_adjust_link(dev); | ||
785 | |||
786 | spin_unlock_irqrestore(&fep->lock, flags); | ||
787 | } | ||
788 | |||
789 | static int fs_init_phy(struct net_device *dev) | ||
790 | { | ||
791 | struct fs_enet_private *fep = netdev_priv(dev); | ||
792 | struct phy_device *phydev; | ||
793 | |||
794 | fep->oldlink = 0; | ||
795 | fep->oldspeed = 0; | ||
796 | fep->oldduplex = -1; | ||
797 | |||
798 | phydev = of_phy_connect(dev, fep->fpi->phy_node, &fs_adjust_link, 0, | ||
799 | PHY_INTERFACE_MODE_MII); | ||
800 | if (!phydev) { | ||
801 | phydev = of_phy_connect_fixed_link(dev, &fs_adjust_link, | ||
802 | PHY_INTERFACE_MODE_MII); | ||
803 | } | ||
804 | if (!phydev) { | ||
805 | dev_err(&dev->dev, "Could not attach to PHY\n"); | ||
806 | return -ENODEV; | ||
807 | } | ||
808 | |||
809 | fep->phydev = phydev; | ||
810 | |||
811 | return 0; | ||
812 | } | ||
813 | |||
814 | static int fs_enet_open(struct net_device *dev) | ||
815 | { | ||
816 | struct fs_enet_private *fep = netdev_priv(dev); | ||
817 | int r; | ||
818 | int err; | ||
819 | |||
820 | /* to initialize the fep->cur_rx,... */ | ||
821 | /* not doing this, will cause a crash in fs_enet_rx_napi */ | ||
822 | fs_init_bds(fep->ndev); | ||
823 | |||
824 | if (fep->fpi->use_napi) | ||
825 | napi_enable(&fep->napi); | ||
826 | |||
827 | /* Install our interrupt handler. */ | ||
828 | r = request_irq(fep->interrupt, fs_enet_interrupt, IRQF_SHARED, | ||
829 | "fs_enet-mac", dev); | ||
830 | if (r != 0) { | ||
831 | dev_err(fep->dev, "Could not allocate FS_ENET IRQ!"); | ||
832 | if (fep->fpi->use_napi) | ||
833 | napi_disable(&fep->napi); | ||
834 | return -EINVAL; | ||
835 | } | ||
836 | |||
837 | err = fs_init_phy(dev); | ||
838 | if (err) { | ||
839 | free_irq(fep->interrupt, dev); | ||
840 | if (fep->fpi->use_napi) | ||
841 | napi_disable(&fep->napi); | ||
842 | return err; | ||
843 | } | ||
844 | phy_start(fep->phydev); | ||
845 | |||
846 | netif_start_queue(dev); | ||
847 | |||
848 | return 0; | ||
849 | } | ||
850 | |||
851 | static int fs_enet_close(struct net_device *dev) | ||
852 | { | ||
853 | struct fs_enet_private *fep = netdev_priv(dev); | ||
854 | unsigned long flags; | ||
855 | |||
856 | netif_stop_queue(dev); | ||
857 | netif_carrier_off(dev); | ||
858 | if (fep->fpi->use_napi) | ||
859 | napi_disable(&fep->napi); | ||
860 | phy_stop(fep->phydev); | ||
861 | |||
862 | spin_lock_irqsave(&fep->lock, flags); | ||
863 | spin_lock(&fep->tx_lock); | ||
864 | (*fep->ops->stop)(dev); | ||
865 | spin_unlock(&fep->tx_lock); | ||
866 | spin_unlock_irqrestore(&fep->lock, flags); | ||
867 | |||
868 | /* release any irqs */ | ||
869 | phy_disconnect(fep->phydev); | ||
870 | fep->phydev = NULL; | ||
871 | free_irq(fep->interrupt, dev); | ||
872 | |||
873 | return 0; | ||
874 | } | ||
875 | |||
876 | static struct net_device_stats *fs_enet_get_stats(struct net_device *dev) | ||
877 | { | ||
878 | struct fs_enet_private *fep = netdev_priv(dev); | ||
879 | return &fep->stats; | ||
880 | } | ||
881 | |||
882 | /*************************************************************************/ | ||
883 | |||
884 | static void fs_get_drvinfo(struct net_device *dev, | ||
885 | struct ethtool_drvinfo *info) | ||
886 | { | ||
887 | strcpy(info->driver, DRV_MODULE_NAME); | ||
888 | strcpy(info->version, DRV_MODULE_VERSION); | ||
889 | } | ||
890 | |||
891 | static int fs_get_regs_len(struct net_device *dev) | ||
892 | { | ||
893 | struct fs_enet_private *fep = netdev_priv(dev); | ||
894 | |||
895 | return (*fep->ops->get_regs_len)(dev); | ||
896 | } | ||
897 | |||
898 | static void fs_get_regs(struct net_device *dev, struct ethtool_regs *regs, | ||
899 | void *p) | ||
900 | { | ||
901 | struct fs_enet_private *fep = netdev_priv(dev); | ||
902 | unsigned long flags; | ||
903 | int r, len; | ||
904 | |||
905 | len = regs->len; | ||
906 | |||
907 | spin_lock_irqsave(&fep->lock, flags); | ||
908 | r = (*fep->ops->get_regs)(dev, p, &len); | ||
909 | spin_unlock_irqrestore(&fep->lock, flags); | ||
910 | |||
911 | if (r == 0) | ||
912 | regs->version = 0; | ||
913 | } | ||
914 | |||
915 | static int fs_get_settings(struct net_device *dev, struct ethtool_cmd *cmd) | ||
916 | { | ||
917 | struct fs_enet_private *fep = netdev_priv(dev); | ||
918 | |||
919 | if (!fep->phydev) | ||
920 | return -ENODEV; | ||
921 | |||
922 | return phy_ethtool_gset(fep->phydev, cmd); | ||
923 | } | ||
924 | |||
925 | static int fs_set_settings(struct net_device *dev, struct ethtool_cmd *cmd) | ||
926 | { | ||
927 | struct fs_enet_private *fep = netdev_priv(dev); | ||
928 | |||
929 | if (!fep->phydev) | ||
930 | return -ENODEV; | ||
931 | |||
932 | return phy_ethtool_sset(fep->phydev, cmd); | ||
933 | } | ||
934 | |||
935 | static int fs_nway_reset(struct net_device *dev) | ||
936 | { | ||
937 | return 0; | ||
938 | } | ||
939 | |||
940 | static u32 fs_get_msglevel(struct net_device *dev) | ||
941 | { | ||
942 | struct fs_enet_private *fep = netdev_priv(dev); | ||
943 | return fep->msg_enable; | ||
944 | } | ||
945 | |||
946 | static void fs_set_msglevel(struct net_device *dev, u32 value) | ||
947 | { | ||
948 | struct fs_enet_private *fep = netdev_priv(dev); | ||
949 | fep->msg_enable = value; | ||
950 | } | ||
951 | |||
952 | static const struct ethtool_ops fs_ethtool_ops = { | ||
953 | .get_drvinfo = fs_get_drvinfo, | ||
954 | .get_regs_len = fs_get_regs_len, | ||
955 | .get_settings = fs_get_settings, | ||
956 | .set_settings = fs_set_settings, | ||
957 | .nway_reset = fs_nway_reset, | ||
958 | .get_link = ethtool_op_get_link, | ||
959 | .get_msglevel = fs_get_msglevel, | ||
960 | .set_msglevel = fs_set_msglevel, | ||
961 | .get_regs = fs_get_regs, | ||
962 | }; | ||
963 | |||
964 | static int fs_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) | ||
965 | { | ||
966 | struct fs_enet_private *fep = netdev_priv(dev); | ||
967 | |||
968 | if (!netif_running(dev)) | ||
969 | return -EINVAL; | ||
970 | |||
971 | return phy_mii_ioctl(fep->phydev, rq, cmd); | ||
972 | } | ||
973 | |||
974 | extern int fs_mii_connect(struct net_device *dev); | ||
975 | extern void fs_mii_disconnect(struct net_device *dev); | ||
976 | |||
977 | /**************************************************************************************/ | ||
978 | |||
979 | #ifdef CONFIG_FS_ENET_HAS_FEC | ||
980 | #define IS_FEC(match) ((match)->data == &fs_fec_ops) | ||
981 | #else | ||
982 | #define IS_FEC(match) 0 | ||
983 | #endif | ||
984 | |||
985 | static const struct net_device_ops fs_enet_netdev_ops = { | ||
986 | .ndo_open = fs_enet_open, | ||
987 | .ndo_stop = fs_enet_close, | ||
988 | .ndo_get_stats = fs_enet_get_stats, | ||
989 | .ndo_start_xmit = fs_enet_start_xmit, | ||
990 | .ndo_tx_timeout = fs_timeout, | ||
991 | .ndo_set_multicast_list = fs_set_multicast_list, | ||
992 | .ndo_do_ioctl = fs_ioctl, | ||
993 | .ndo_validate_addr = eth_validate_addr, | ||
994 | .ndo_set_mac_address = eth_mac_addr, | ||
995 | .ndo_change_mtu = eth_change_mtu, | ||
996 | #ifdef CONFIG_NET_POLL_CONTROLLER | ||
997 | .ndo_poll_controller = fs_enet_netpoll, | ||
998 | #endif | ||
999 | }; | ||
1000 | |||
1001 | static struct of_device_id fs_enet_match[]; | ||
1002 | static int __devinit fs_enet_probe(struct platform_device *ofdev) | ||
1003 | { | ||
1004 | const struct of_device_id *match; | ||
1005 | struct net_device *ndev; | ||
1006 | struct fs_enet_private *fep; | ||
1007 | struct fs_platform_info *fpi; | ||
1008 | const u32 *data; | ||
1009 | const u8 *mac_addr; | ||
1010 | int privsize, len, ret = -ENODEV; | ||
1011 | |||
1012 | match = of_match_device(fs_enet_match, &ofdev->dev); | ||
1013 | if (!match) | ||
1014 | return -EINVAL; | ||
1015 | |||
1016 | fpi = kzalloc(sizeof(*fpi), GFP_KERNEL); | ||
1017 | if (!fpi) | ||
1018 | return -ENOMEM; | ||
1019 | |||
1020 | if (!IS_FEC(match)) { | ||
1021 | data = of_get_property(ofdev->dev.of_node, "fsl,cpm-command", &len); | ||
1022 | if (!data || len != 4) | ||
1023 | goto out_free_fpi; | ||
1024 | |||
1025 | fpi->cp_command = *data; | ||
1026 | } | ||
1027 | |||
1028 | fpi->rx_ring = 32; | ||
1029 | fpi->tx_ring = 32; | ||
1030 | fpi->rx_copybreak = 240; | ||
1031 | fpi->use_napi = 1; | ||
1032 | fpi->napi_weight = 17; | ||
1033 | fpi->phy_node = of_parse_phandle(ofdev->dev.of_node, "phy-handle", 0); | ||
1034 | if ((!fpi->phy_node) && (!of_get_property(ofdev->dev.of_node, "fixed-link", | ||
1035 | NULL))) | ||
1036 | goto out_free_fpi; | ||
1037 | |||
1038 | privsize = sizeof(*fep) + | ||
1039 | sizeof(struct sk_buff **) * | ||
1040 | (fpi->rx_ring + fpi->tx_ring); | ||
1041 | |||
1042 | ndev = alloc_etherdev(privsize); | ||
1043 | if (!ndev) { | ||
1044 | ret = -ENOMEM; | ||
1045 | goto out_put; | ||
1046 | } | ||
1047 | |||
1048 | SET_NETDEV_DEV(ndev, &ofdev->dev); | ||
1049 | dev_set_drvdata(&ofdev->dev, ndev); | ||
1050 | |||
1051 | fep = netdev_priv(ndev); | ||
1052 | fep->dev = &ofdev->dev; | ||
1053 | fep->ndev = ndev; | ||
1054 | fep->fpi = fpi; | ||
1055 | fep->ops = match->data; | ||
1056 | |||
1057 | ret = fep->ops->setup_data(ndev); | ||
1058 | if (ret) | ||
1059 | goto out_free_dev; | ||
1060 | |||
1061 | fep->rx_skbuff = (struct sk_buff **)&fep[1]; | ||
1062 | fep->tx_skbuff = fep->rx_skbuff + fpi->rx_ring; | ||
1063 | |||
1064 | spin_lock_init(&fep->lock); | ||
1065 | spin_lock_init(&fep->tx_lock); | ||
1066 | |||
1067 | mac_addr = of_get_mac_address(ofdev->dev.of_node); | ||
1068 | if (mac_addr) | ||
1069 | memcpy(ndev->dev_addr, mac_addr, 6); | ||
1070 | |||
1071 | ret = fep->ops->allocate_bd(ndev); | ||
1072 | if (ret) | ||
1073 | goto out_cleanup_data; | ||
1074 | |||
1075 | fep->rx_bd_base = fep->ring_base; | ||
1076 | fep->tx_bd_base = fep->rx_bd_base + fpi->rx_ring; | ||
1077 | |||
1078 | fep->tx_ring = fpi->tx_ring; | ||
1079 | fep->rx_ring = fpi->rx_ring; | ||
1080 | |||
1081 | ndev->netdev_ops = &fs_enet_netdev_ops; | ||
1082 | ndev->watchdog_timeo = 2 * HZ; | ||
1083 | if (fpi->use_napi) | ||
1084 | netif_napi_add(ndev, &fep->napi, fs_enet_rx_napi, | ||
1085 | fpi->napi_weight); | ||
1086 | |||
1087 | ndev->ethtool_ops = &fs_ethtool_ops; | ||
1088 | |||
1089 | init_timer(&fep->phy_timer_list); | ||
1090 | |||
1091 | netif_carrier_off(ndev); | ||
1092 | |||
1093 | ret = register_netdev(ndev); | ||
1094 | if (ret) | ||
1095 | goto out_free_bd; | ||
1096 | |||
1097 | pr_info("%s: fs_enet: %pM\n", ndev->name, ndev->dev_addr); | ||
1098 | |||
1099 | return 0; | ||
1100 | |||
1101 | out_free_bd: | ||
1102 | fep->ops->free_bd(ndev); | ||
1103 | out_cleanup_data: | ||
1104 | fep->ops->cleanup_data(ndev); | ||
1105 | out_free_dev: | ||
1106 | free_netdev(ndev); | ||
1107 | dev_set_drvdata(&ofdev->dev, NULL); | ||
1108 | out_put: | ||
1109 | of_node_put(fpi->phy_node); | ||
1110 | out_free_fpi: | ||
1111 | kfree(fpi); | ||
1112 | return ret; | ||
1113 | } | ||
1114 | |||
1115 | static int fs_enet_remove(struct platform_device *ofdev) | ||
1116 | { | ||
1117 | struct net_device *ndev = dev_get_drvdata(&ofdev->dev); | ||
1118 | struct fs_enet_private *fep = netdev_priv(ndev); | ||
1119 | |||
1120 | unregister_netdev(ndev); | ||
1121 | |||
1122 | fep->ops->free_bd(ndev); | ||
1123 | fep->ops->cleanup_data(ndev); | ||
1124 | dev_set_drvdata(fep->dev, NULL); | ||
1125 | of_node_put(fep->fpi->phy_node); | ||
1126 | free_netdev(ndev); | ||
1127 | return 0; | ||
1128 | } | ||
1129 | |||
1130 | static struct of_device_id fs_enet_match[] = { | ||
1131 | #ifdef CONFIG_FS_ENET_HAS_SCC | ||
1132 | { | ||
1133 | .compatible = "fsl,cpm1-scc-enet", | ||
1134 | .data = (void *)&fs_scc_ops, | ||
1135 | }, | ||
1136 | { | ||
1137 | .compatible = "fsl,cpm2-scc-enet", | ||
1138 | .data = (void *)&fs_scc_ops, | ||
1139 | }, | ||
1140 | #endif | ||
1141 | #ifdef CONFIG_FS_ENET_HAS_FCC | ||
1142 | { | ||
1143 | .compatible = "fsl,cpm2-fcc-enet", | ||
1144 | .data = (void *)&fs_fcc_ops, | ||
1145 | }, | ||
1146 | #endif | ||
1147 | #ifdef CONFIG_FS_ENET_HAS_FEC | ||
1148 | #ifdef CONFIG_FS_ENET_MPC5121_FEC | ||
1149 | { | ||
1150 | .compatible = "fsl,mpc5121-fec", | ||
1151 | .data = (void *)&fs_fec_ops, | ||
1152 | }, | ||
1153 | #else | ||
1154 | { | ||
1155 | .compatible = "fsl,pq1-fec-enet", | ||
1156 | .data = (void *)&fs_fec_ops, | ||
1157 | }, | ||
1158 | #endif | ||
1159 | #endif | ||
1160 | {} | ||
1161 | }; | ||
1162 | MODULE_DEVICE_TABLE(of, fs_enet_match); | ||
1163 | |||
1164 | static struct platform_driver fs_enet_driver = { | ||
1165 | .driver = { | ||
1166 | .owner = THIS_MODULE, | ||
1167 | .name = "fs_enet", | ||
1168 | .of_match_table = fs_enet_match, | ||
1169 | }, | ||
1170 | .probe = fs_enet_probe, | ||
1171 | .remove = fs_enet_remove, | ||
1172 | }; | ||
1173 | |||
1174 | static int __init fs_init(void) | ||
1175 | { | ||
1176 | return platform_driver_register(&fs_enet_driver); | ||
1177 | } | ||
1178 | |||
1179 | static void __exit fs_cleanup(void) | ||
1180 | { | ||
1181 | platform_driver_unregister(&fs_enet_driver); | ||
1182 | } | ||
1183 | |||
1184 | #ifdef CONFIG_NET_POLL_CONTROLLER | ||
1185 | static void fs_enet_netpoll(struct net_device *dev) | ||
1186 | { | ||
1187 | disable_irq(dev->irq); | ||
1188 | fs_enet_interrupt(dev->irq, dev); | ||
1189 | enable_irq(dev->irq); | ||
1190 | } | ||
1191 | #endif | ||
1192 | |||
1193 | /**************************************************************************************/ | ||
1194 | |||
1195 | module_init(fs_init); | ||
1196 | module_exit(fs_cleanup); | ||
diff --git a/drivers/net/fs_enet/fs_enet.h b/drivers/net/fs_enet/fs_enet.h new file mode 100644 index 00000000000..1ece4b1a689 --- /dev/null +++ b/drivers/net/fs_enet/fs_enet.h | |||
@@ -0,0 +1,244 @@ | |||
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/list.h> | ||
8 | #include <linux/phy.h> | ||
9 | #include <linux/dma-mapping.h> | ||
10 | |||
11 | #include <linux/fs_enet_pd.h> | ||
12 | #include <asm/fs_pd.h> | ||
13 | |||
14 | #ifdef CONFIG_CPM1 | ||
15 | #include <asm/cpm1.h> | ||
16 | #endif | ||
17 | |||
18 | #if defined(CONFIG_FS_ENET_HAS_FEC) | ||
19 | #include <asm/cpm.h> | ||
20 | |||
21 | #if defined(CONFIG_FS_ENET_MPC5121_FEC) | ||
22 | /* MPC5121 FEC has different register layout */ | ||
23 | struct fec { | ||
24 | u32 fec_reserved0; | ||
25 | u32 fec_ievent; /* Interrupt event reg */ | ||
26 | u32 fec_imask; /* Interrupt mask reg */ | ||
27 | u32 fec_reserved1; | ||
28 | u32 fec_r_des_active; /* Receive descriptor reg */ | ||
29 | u32 fec_x_des_active; /* Transmit descriptor reg */ | ||
30 | u32 fec_reserved2[3]; | ||
31 | u32 fec_ecntrl; /* Ethernet control reg */ | ||
32 | u32 fec_reserved3[6]; | ||
33 | u32 fec_mii_data; /* MII manage frame reg */ | ||
34 | u32 fec_mii_speed; /* MII speed control reg */ | ||
35 | u32 fec_reserved4[7]; | ||
36 | u32 fec_mib_ctrlstat; /* MIB control/status reg */ | ||
37 | u32 fec_reserved5[7]; | ||
38 | u32 fec_r_cntrl; /* Receive control reg */ | ||
39 | u32 fec_reserved6[15]; | ||
40 | u32 fec_x_cntrl; /* Transmit Control reg */ | ||
41 | u32 fec_reserved7[7]; | ||
42 | u32 fec_addr_low; /* Low 32bits MAC address */ | ||
43 | u32 fec_addr_high; /* High 16bits MAC address */ | ||
44 | u32 fec_opd; /* Opcode + Pause duration */ | ||
45 | u32 fec_reserved8[10]; | ||
46 | u32 fec_hash_table_high; /* High 32bits hash table */ | ||
47 | u32 fec_hash_table_low; /* Low 32bits hash table */ | ||
48 | u32 fec_grp_hash_table_high; /* High 32bits hash table */ | ||
49 | u32 fec_grp_hash_table_low; /* Low 32bits hash table */ | ||
50 | u32 fec_reserved9[7]; | ||
51 | u32 fec_x_wmrk; /* FIFO transmit water mark */ | ||
52 | u32 fec_reserved10; | ||
53 | u32 fec_r_bound; /* FIFO receive bound reg */ | ||
54 | u32 fec_r_fstart; /* FIFO receive start reg */ | ||
55 | u32 fec_reserved11[11]; | ||
56 | u32 fec_r_des_start; /* Receive descriptor ring */ | ||
57 | u32 fec_x_des_start; /* Transmit descriptor ring */ | ||
58 | u32 fec_r_buff_size; /* Maximum receive buff size */ | ||
59 | u32 fec_reserved12[26]; | ||
60 | u32 fec_dma_control; /* DMA Endian and other ctrl */ | ||
61 | }; | ||
62 | #endif | ||
63 | |||
64 | struct fec_info { | ||
65 | struct fec __iomem *fecp; | ||
66 | u32 mii_speed; | ||
67 | }; | ||
68 | #endif | ||
69 | |||
70 | #ifdef CONFIG_CPM2 | ||
71 | #include <asm/cpm2.h> | ||
72 | #endif | ||
73 | |||
74 | /* hw driver ops */ | ||
75 | struct fs_ops { | ||
76 | int (*setup_data)(struct net_device *dev); | ||
77 | int (*allocate_bd)(struct net_device *dev); | ||
78 | void (*free_bd)(struct net_device *dev); | ||
79 | void (*cleanup_data)(struct net_device *dev); | ||
80 | void (*set_multicast_list)(struct net_device *dev); | ||
81 | void (*adjust_link)(struct net_device *dev); | ||
82 | void (*restart)(struct net_device *dev); | ||
83 | void (*stop)(struct net_device *dev); | ||
84 | void (*napi_clear_rx_event)(struct net_device *dev); | ||
85 | void (*napi_enable_rx)(struct net_device *dev); | ||
86 | void (*napi_disable_rx)(struct net_device *dev); | ||
87 | void (*rx_bd_done)(struct net_device *dev); | ||
88 | void (*tx_kickstart)(struct net_device *dev); | ||
89 | u32 (*get_int_events)(struct net_device *dev); | ||
90 | void (*clear_int_events)(struct net_device *dev, u32 int_events); | ||
91 | void (*ev_error)(struct net_device *dev, u32 int_events); | ||
92 | int (*get_regs)(struct net_device *dev, void *p, int *sizep); | ||
93 | int (*get_regs_len)(struct net_device *dev); | ||
94 | void (*tx_restart)(struct net_device *dev); | ||
95 | }; | ||
96 | |||
97 | struct phy_info { | ||
98 | unsigned int id; | ||
99 | const char *name; | ||
100 | void (*startup) (struct net_device * dev); | ||
101 | void (*shutdown) (struct net_device * dev); | ||
102 | void (*ack_int) (struct net_device * dev); | ||
103 | }; | ||
104 | |||
105 | /* The FEC stores dest/src/type, data, and checksum for receive packets. | ||
106 | */ | ||
107 | #define MAX_MTU 1508 /* Allow fullsized pppoe packets over VLAN */ | ||
108 | #define MIN_MTU 46 /* this is data size */ | ||
109 | #define CRC_LEN 4 | ||
110 | |||
111 | #define PKT_MAXBUF_SIZE (MAX_MTU+ETH_HLEN+CRC_LEN) | ||
112 | #define PKT_MINBUF_SIZE (MIN_MTU+ETH_HLEN+CRC_LEN) | ||
113 | |||
114 | /* Must be a multiple of 32 (to cover both FEC & FCC) */ | ||
115 | #define PKT_MAXBLR_SIZE ((PKT_MAXBUF_SIZE + 31) & ~31) | ||
116 | /* This is needed so that invalidate_xxx wont invalidate too much */ | ||
117 | #define ENET_RX_ALIGN 16 | ||
118 | #define ENET_RX_FRSIZE L1_CACHE_ALIGN(PKT_MAXBUF_SIZE + ENET_RX_ALIGN - 1) | ||
119 | |||
120 | struct fs_enet_private { | ||
121 | struct napi_struct napi; | ||
122 | struct device *dev; /* pointer back to the device (must be initialized first) */ | ||
123 | struct net_device *ndev; | ||
124 | spinlock_t lock; /* during all ops except TX pckt processing */ | ||
125 | spinlock_t tx_lock; /* during fs_start_xmit and fs_tx */ | ||
126 | struct fs_platform_info *fpi; | ||
127 | const struct fs_ops *ops; | ||
128 | int rx_ring, tx_ring; | ||
129 | dma_addr_t ring_mem_addr; | ||
130 | void __iomem *ring_base; | ||
131 | struct sk_buff **rx_skbuff; | ||
132 | struct sk_buff **tx_skbuff; | ||
133 | cbd_t __iomem *rx_bd_base; /* Address of Rx and Tx buffers. */ | ||
134 | cbd_t __iomem *tx_bd_base; | ||
135 | cbd_t __iomem *dirty_tx; /* ring entries to be free()ed. */ | ||
136 | cbd_t __iomem *cur_rx; | ||
137 | cbd_t __iomem *cur_tx; | ||
138 | int tx_free; | ||
139 | struct net_device_stats stats; | ||
140 | struct timer_list phy_timer_list; | ||
141 | const struct phy_info *phy; | ||
142 | u32 msg_enable; | ||
143 | struct mii_if_info mii_if; | ||
144 | unsigned int last_mii_status; | ||
145 | int interrupt; | ||
146 | |||
147 | struct phy_device *phydev; | ||
148 | int oldduplex, oldspeed, oldlink; /* current settings */ | ||
149 | |||
150 | /* event masks */ | ||
151 | u32 ev_napi_rx; /* mask of NAPI rx events */ | ||
152 | u32 ev_rx; /* rx event mask */ | ||
153 | u32 ev_tx; /* tx event mask */ | ||
154 | u32 ev_err; /* error event mask */ | ||
155 | |||
156 | u16 bd_rx_empty; /* mask of BD rx empty */ | ||
157 | u16 bd_rx_err; /* mask of BD rx errors */ | ||
158 | |||
159 | union { | ||
160 | struct { | ||
161 | int idx; /* FEC1 = 0, FEC2 = 1 */ | ||
162 | void __iomem *fecp; /* hw registers */ | ||
163 | u32 hthi, htlo; /* state for multicast */ | ||
164 | } fec; | ||
165 | |||
166 | struct { | ||
167 | int idx; /* FCC1-3 = 0-2 */ | ||
168 | void __iomem *fccp; /* hw registers */ | ||
169 | void __iomem *ep; /* parameter ram */ | ||
170 | void __iomem *fcccp; /* hw registers cont. */ | ||
171 | void __iomem *mem; /* FCC DPRAM */ | ||
172 | u32 gaddrh, gaddrl; /* group address */ | ||
173 | } fcc; | ||
174 | |||
175 | struct { | ||
176 | int idx; /* FEC1 = 0, FEC2 = 1 */ | ||
177 | void __iomem *sccp; /* hw registers */ | ||
178 | void __iomem *ep; /* parameter ram */ | ||
179 | u32 hthi, htlo; /* state for multicast */ | ||
180 | } scc; | ||
181 | |||
182 | }; | ||
183 | }; | ||
184 | |||
185 | /***************************************************************************/ | ||
186 | |||
187 | void fs_init_bds(struct net_device *dev); | ||
188 | void fs_cleanup_bds(struct net_device *dev); | ||
189 | |||
190 | /***************************************************************************/ | ||
191 | |||
192 | #define DRV_MODULE_NAME "fs_enet" | ||
193 | #define PFX DRV_MODULE_NAME ": " | ||
194 | #define DRV_MODULE_VERSION "1.0" | ||
195 | #define DRV_MODULE_RELDATE "Aug 8, 2005" | ||
196 | |||
197 | /***************************************************************************/ | ||
198 | |||
199 | int fs_enet_platform_init(void); | ||
200 | void fs_enet_platform_cleanup(void); | ||
201 | |||
202 | /***************************************************************************/ | ||
203 | /* buffer descriptor access macros */ | ||
204 | |||
205 | /* access macros */ | ||
206 | #if defined(CONFIG_CPM1) | ||
207 | /* for a a CPM1 __raw_xxx's are sufficient */ | ||
208 | #define __cbd_out32(addr, x) __raw_writel(x, addr) | ||
209 | #define __cbd_out16(addr, x) __raw_writew(x, addr) | ||
210 | #define __cbd_in32(addr) __raw_readl(addr) | ||
211 | #define __cbd_in16(addr) __raw_readw(addr) | ||
212 | #else | ||
213 | /* for others play it safe */ | ||
214 | #define __cbd_out32(addr, x) out_be32(addr, x) | ||
215 | #define __cbd_out16(addr, x) out_be16(addr, x) | ||
216 | #define __cbd_in32(addr) in_be32(addr) | ||
217 | #define __cbd_in16(addr) in_be16(addr) | ||
218 | #endif | ||
219 | |||
220 | /* write */ | ||
221 | #define CBDW_SC(_cbd, _sc) __cbd_out16(&(_cbd)->cbd_sc, (_sc)) | ||
222 | #define CBDW_DATLEN(_cbd, _datlen) __cbd_out16(&(_cbd)->cbd_datlen, (_datlen)) | ||
223 | #define CBDW_BUFADDR(_cbd, _bufaddr) __cbd_out32(&(_cbd)->cbd_bufaddr, (_bufaddr)) | ||
224 | |||
225 | /* read */ | ||
226 | #define CBDR_SC(_cbd) __cbd_in16(&(_cbd)->cbd_sc) | ||
227 | #define CBDR_DATLEN(_cbd) __cbd_in16(&(_cbd)->cbd_datlen) | ||
228 | #define CBDR_BUFADDR(_cbd) __cbd_in32(&(_cbd)->cbd_bufaddr) | ||
229 | |||
230 | /* set bits */ | ||
231 | #define CBDS_SC(_cbd, _sc) CBDW_SC(_cbd, CBDR_SC(_cbd) | (_sc)) | ||
232 | |||
233 | /* clear bits */ | ||
234 | #define CBDC_SC(_cbd, _sc) CBDW_SC(_cbd, CBDR_SC(_cbd) & ~(_sc)) | ||
235 | |||
236 | /*******************************************************************/ | ||
237 | |||
238 | extern const struct fs_ops fs_fec_ops; | ||
239 | extern const struct fs_ops fs_fcc_ops; | ||
240 | extern const struct fs_ops fs_scc_ops; | ||
241 | |||
242 | /*******************************************************************/ | ||
243 | |||
244 | #endif | ||
diff --git a/drivers/net/fs_enet/mac-fcc.c b/drivers/net/fs_enet/mac-fcc.c new file mode 100644 index 00000000000..7583a9572bc --- /dev/null +++ b/drivers/net/fs_enet/mac-fcc.c | |||
@@ -0,0 +1,584 @@ | |||
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/module.h> | ||
16 | #include <linux/kernel.h> | ||
17 | #include <linux/types.h> | ||
18 | #include <linux/string.h> | ||
19 | #include <linux/ptrace.h> | ||
20 | #include <linux/errno.h> | ||
21 | #include <linux/ioport.h> | ||
22 | #include <linux/interrupt.h> | ||
23 | #include <linux/init.h> | ||
24 | #include <linux/delay.h> | ||
25 | #include <linux/netdevice.h> | ||
26 | #include <linux/etherdevice.h> | ||
27 | #include <linux/skbuff.h> | ||
28 | #include <linux/spinlock.h> | ||
29 | #include <linux/mii.h> | ||
30 | #include <linux/ethtool.h> | ||
31 | #include <linux/bitops.h> | ||
32 | #include <linux/fs.h> | ||
33 | #include <linux/platform_device.h> | ||
34 | #include <linux/phy.h> | ||
35 | #include <linux/of_device.h> | ||
36 | #include <linux/gfp.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 | /* write, read, set bits, clear bits */ | ||
53 | #define W32(_p, _m, _v) out_be32(&(_p)->_m, (_v)) | ||
54 | #define R32(_p, _m) in_be32(&(_p)->_m) | ||
55 | #define S32(_p, _m, _v) W32(_p, _m, R32(_p, _m) | (_v)) | ||
56 | #define C32(_p, _m, _v) W32(_p, _m, R32(_p, _m) & ~(_v)) | ||
57 | |||
58 | #define W16(_p, _m, _v) out_be16(&(_p)->_m, (_v)) | ||
59 | #define R16(_p, _m) in_be16(&(_p)->_m) | ||
60 | #define S16(_p, _m, _v) W16(_p, _m, R16(_p, _m) | (_v)) | ||
61 | #define C16(_p, _m, _v) W16(_p, _m, R16(_p, _m) & ~(_v)) | ||
62 | |||
63 | #define W8(_p, _m, _v) out_8(&(_p)->_m, (_v)) | ||
64 | #define R8(_p, _m) in_8(&(_p)->_m) | ||
65 | #define S8(_p, _m, _v) W8(_p, _m, R8(_p, _m) | (_v)) | ||
66 | #define C8(_p, _m, _v) W8(_p, _m, R8(_p, _m) & ~(_v)) | ||
67 | |||
68 | /*************************************************/ | ||
69 | |||
70 | #define FCC_MAX_MULTICAST_ADDRS 64 | ||
71 | |||
72 | #define mk_mii_read(REG) (0x60020000 | ((REG & 0x1f) << 18)) | ||
73 | #define mk_mii_write(REG, VAL) (0x50020000 | ((REG & 0x1f) << 18) | (VAL & 0xffff)) | ||
74 | #define mk_mii_end 0 | ||
75 | |||
76 | #define MAX_CR_CMD_LOOPS 10000 | ||
77 | |||
78 | static inline int fcc_cr_cmd(struct fs_enet_private *fep, u32 op) | ||
79 | { | ||
80 | const struct fs_platform_info *fpi = fep->fpi; | ||
81 | |||
82 | return cpm_command(fpi->cp_command, op); | ||
83 | } | ||
84 | |||
85 | static int do_pd_setup(struct fs_enet_private *fep) | ||
86 | { | ||
87 | struct platform_device *ofdev = to_platform_device(fep->dev); | ||
88 | struct fs_platform_info *fpi = fep->fpi; | ||
89 | int ret = -EINVAL; | ||
90 | |||
91 | fep->interrupt = of_irq_to_resource(ofdev->dev.of_node, 0, NULL); | ||
92 | if (fep->interrupt == NO_IRQ) | ||
93 | goto out; | ||
94 | |||
95 | fep->fcc.fccp = of_iomap(ofdev->dev.of_node, 0); | ||
96 | if (!fep->fcc.fccp) | ||
97 | goto out; | ||
98 | |||
99 | fep->fcc.ep = of_iomap(ofdev->dev.of_node, 1); | ||
100 | if (!fep->fcc.ep) | ||
101 | goto out_fccp; | ||
102 | |||
103 | fep->fcc.fcccp = of_iomap(ofdev->dev.of_node, 2); | ||
104 | if (!fep->fcc.fcccp) | ||
105 | goto out_ep; | ||
106 | |||
107 | fep->fcc.mem = (void __iomem *)cpm2_immr; | ||
108 | fpi->dpram_offset = cpm_dpalloc(128, 32); | ||
109 | if (IS_ERR_VALUE(fpi->dpram_offset)) { | ||
110 | ret = fpi->dpram_offset; | ||
111 | goto out_fcccp; | ||
112 | } | ||
113 | |||
114 | return 0; | ||
115 | |||
116 | out_fcccp: | ||
117 | iounmap(fep->fcc.fcccp); | ||
118 | out_ep: | ||
119 | iounmap(fep->fcc.ep); | ||
120 | out_fccp: | ||
121 | iounmap(fep->fcc.fccp); | ||
122 | out: | ||
123 | return ret; | ||
124 | } | ||
125 | |||
126 | #define FCC_NAPI_RX_EVENT_MSK (FCC_ENET_RXF | FCC_ENET_RXB) | ||
127 | #define FCC_RX_EVENT (FCC_ENET_RXF) | ||
128 | #define FCC_TX_EVENT (FCC_ENET_TXB) | ||
129 | #define FCC_ERR_EVENT_MSK (FCC_ENET_TXE) | ||
130 | |||
131 | static int setup_data(struct net_device *dev) | ||
132 | { | ||
133 | struct fs_enet_private *fep = netdev_priv(dev); | ||
134 | |||
135 | if (do_pd_setup(fep) != 0) | ||
136 | return -EINVAL; | ||
137 | |||
138 | fep->ev_napi_rx = FCC_NAPI_RX_EVENT_MSK; | ||
139 | fep->ev_rx = FCC_RX_EVENT; | ||
140 | fep->ev_tx = FCC_TX_EVENT; | ||
141 | fep->ev_err = FCC_ERR_EVENT_MSK; | ||
142 | |||
143 | return 0; | ||
144 | } | ||
145 | |||
146 | static int allocate_bd(struct net_device *dev) | ||
147 | { | ||
148 | struct fs_enet_private *fep = netdev_priv(dev); | ||
149 | const struct fs_platform_info *fpi = fep->fpi; | ||
150 | |||
151 | fep->ring_base = (void __iomem __force *)dma_alloc_coherent(fep->dev, | ||
152 | (fpi->tx_ring + fpi->rx_ring) * | ||
153 | sizeof(cbd_t), &fep->ring_mem_addr, | ||
154 | GFP_KERNEL); | ||
155 | if (fep->ring_base == NULL) | ||
156 | return -ENOMEM; | ||
157 | |||
158 | return 0; | ||
159 | } | ||
160 | |||
161 | static void free_bd(struct net_device *dev) | ||
162 | { | ||
163 | struct fs_enet_private *fep = netdev_priv(dev); | ||
164 | const struct fs_platform_info *fpi = fep->fpi; | ||
165 | |||
166 | if (fep->ring_base) | ||
167 | dma_free_coherent(fep->dev, | ||
168 | (fpi->tx_ring + fpi->rx_ring) * sizeof(cbd_t), | ||
169 | (void __force *)fep->ring_base, fep->ring_mem_addr); | ||
170 | } | ||
171 | |||
172 | static void cleanup_data(struct net_device *dev) | ||
173 | { | ||
174 | /* nothing */ | ||
175 | } | ||
176 | |||
177 | static void set_promiscuous_mode(struct net_device *dev) | ||
178 | { | ||
179 | struct fs_enet_private *fep = netdev_priv(dev); | ||
180 | fcc_t __iomem *fccp = fep->fcc.fccp; | ||
181 | |||
182 | S32(fccp, fcc_fpsmr, FCC_PSMR_PRO); | ||
183 | } | ||
184 | |||
185 | static void set_multicast_start(struct net_device *dev) | ||
186 | { | ||
187 | struct fs_enet_private *fep = netdev_priv(dev); | ||
188 | fcc_enet_t __iomem *ep = fep->fcc.ep; | ||
189 | |||
190 | W32(ep, fen_gaddrh, 0); | ||
191 | W32(ep, fen_gaddrl, 0); | ||
192 | } | ||
193 | |||
194 | static void set_multicast_one(struct net_device *dev, const u8 *mac) | ||
195 | { | ||
196 | struct fs_enet_private *fep = netdev_priv(dev); | ||
197 | fcc_enet_t __iomem *ep = fep->fcc.ep; | ||
198 | u16 taddrh, taddrm, taddrl; | ||
199 | |||
200 | taddrh = ((u16)mac[5] << 8) | mac[4]; | ||
201 | taddrm = ((u16)mac[3] << 8) | mac[2]; | ||
202 | taddrl = ((u16)mac[1] << 8) | mac[0]; | ||
203 | |||
204 | W16(ep, fen_taddrh, taddrh); | ||
205 | W16(ep, fen_taddrm, taddrm); | ||
206 | W16(ep, fen_taddrl, taddrl); | ||
207 | fcc_cr_cmd(fep, CPM_CR_SET_GADDR); | ||
208 | } | ||
209 | |||
210 | static void set_multicast_finish(struct net_device *dev) | ||
211 | { | ||
212 | struct fs_enet_private *fep = netdev_priv(dev); | ||
213 | fcc_t __iomem *fccp = fep->fcc.fccp; | ||
214 | fcc_enet_t __iomem *ep = fep->fcc.ep; | ||
215 | |||
216 | /* clear promiscuous always */ | ||
217 | C32(fccp, fcc_fpsmr, FCC_PSMR_PRO); | ||
218 | |||
219 | /* if all multi or too many multicasts; just enable all */ | ||
220 | if ((dev->flags & IFF_ALLMULTI) != 0 || | ||
221 | netdev_mc_count(dev) > FCC_MAX_MULTICAST_ADDRS) { | ||
222 | |||
223 | W32(ep, fen_gaddrh, 0xffffffff); | ||
224 | W32(ep, fen_gaddrl, 0xffffffff); | ||
225 | } | ||
226 | |||
227 | /* read back */ | ||
228 | fep->fcc.gaddrh = R32(ep, fen_gaddrh); | ||
229 | fep->fcc.gaddrl = R32(ep, fen_gaddrl); | ||
230 | } | ||
231 | |||
232 | static void set_multicast_list(struct net_device *dev) | ||
233 | { | ||
234 | struct netdev_hw_addr *ha; | ||
235 | |||
236 | if ((dev->flags & IFF_PROMISC) == 0) { | ||
237 | set_multicast_start(dev); | ||
238 | netdev_for_each_mc_addr(ha, dev) | ||
239 | set_multicast_one(dev, ha->addr); | ||
240 | set_multicast_finish(dev); | ||
241 | } else | ||
242 | set_promiscuous_mode(dev); | ||
243 | } | ||
244 | |||
245 | static void restart(struct net_device *dev) | ||
246 | { | ||
247 | struct fs_enet_private *fep = netdev_priv(dev); | ||
248 | const struct fs_platform_info *fpi = fep->fpi; | ||
249 | fcc_t __iomem *fccp = fep->fcc.fccp; | ||
250 | fcc_c_t __iomem *fcccp = fep->fcc.fcccp; | ||
251 | fcc_enet_t __iomem *ep = fep->fcc.ep; | ||
252 | dma_addr_t rx_bd_base_phys, tx_bd_base_phys; | ||
253 | u16 paddrh, paddrm, paddrl; | ||
254 | const unsigned char *mac; | ||
255 | int i; | ||
256 | |||
257 | C32(fccp, fcc_gfmr, FCC_GFMR_ENR | FCC_GFMR_ENT); | ||
258 | |||
259 | /* clear everything (slow & steady does it) */ | ||
260 | for (i = 0; i < sizeof(*ep); i++) | ||
261 | out_8((u8 __iomem *)ep + i, 0); | ||
262 | |||
263 | /* get physical address */ | ||
264 | rx_bd_base_phys = fep->ring_mem_addr; | ||
265 | tx_bd_base_phys = rx_bd_base_phys + sizeof(cbd_t) * fpi->rx_ring; | ||
266 | |||
267 | /* point to bds */ | ||
268 | W32(ep, fen_genfcc.fcc_rbase, rx_bd_base_phys); | ||
269 | W32(ep, fen_genfcc.fcc_tbase, tx_bd_base_phys); | ||
270 | |||
271 | /* Set maximum bytes per receive buffer. | ||
272 | * It must be a multiple of 32. | ||
273 | */ | ||
274 | W16(ep, fen_genfcc.fcc_mrblr, PKT_MAXBLR_SIZE); | ||
275 | |||
276 | W32(ep, fen_genfcc.fcc_rstate, (CPMFCR_GBL | CPMFCR_EB) << 24); | ||
277 | W32(ep, fen_genfcc.fcc_tstate, (CPMFCR_GBL | CPMFCR_EB) << 24); | ||
278 | |||
279 | /* Allocate space in the reserved FCC area of DPRAM for the | ||
280 | * internal buffers. No one uses this space (yet), so we | ||
281 | * can do this. Later, we will add resource management for | ||
282 | * this area. | ||
283 | */ | ||
284 | |||
285 | W16(ep, fen_genfcc.fcc_riptr, fpi->dpram_offset); | ||
286 | W16(ep, fen_genfcc.fcc_tiptr, fpi->dpram_offset + 32); | ||
287 | |||
288 | W16(ep, fen_padptr, fpi->dpram_offset + 64); | ||
289 | |||
290 | /* fill with special symbol... */ | ||
291 | memset_io(fep->fcc.mem + fpi->dpram_offset + 64, 0x88, 32); | ||
292 | |||
293 | W32(ep, fen_genfcc.fcc_rbptr, 0); | ||
294 | W32(ep, fen_genfcc.fcc_tbptr, 0); | ||
295 | W32(ep, fen_genfcc.fcc_rcrc, 0); | ||
296 | W32(ep, fen_genfcc.fcc_tcrc, 0); | ||
297 | W16(ep, fen_genfcc.fcc_res1, 0); | ||
298 | W32(ep, fen_genfcc.fcc_res2, 0); | ||
299 | |||
300 | /* no CAM */ | ||
301 | W32(ep, fen_camptr, 0); | ||
302 | |||
303 | /* Set CRC preset and mask */ | ||
304 | W32(ep, fen_cmask, 0xdebb20e3); | ||
305 | W32(ep, fen_cpres, 0xffffffff); | ||
306 | |||
307 | W32(ep, fen_crcec, 0); /* CRC Error counter */ | ||
308 | W32(ep, fen_alec, 0); /* alignment error counter */ | ||
309 | W32(ep, fen_disfc, 0); /* discard frame counter */ | ||
310 | W16(ep, fen_retlim, 15); /* Retry limit threshold */ | ||
311 | W16(ep, fen_pper, 0); /* Normal persistence */ | ||
312 | |||
313 | /* set group address */ | ||
314 | W32(ep, fen_gaddrh, fep->fcc.gaddrh); | ||
315 | W32(ep, fen_gaddrl, fep->fcc.gaddrh); | ||
316 | |||
317 | /* Clear hash filter tables */ | ||
318 | W32(ep, fen_iaddrh, 0); | ||
319 | W32(ep, fen_iaddrl, 0); | ||
320 | |||
321 | /* Clear the Out-of-sequence TxBD */ | ||
322 | W16(ep, fen_tfcstat, 0); | ||
323 | W16(ep, fen_tfclen, 0); | ||
324 | W32(ep, fen_tfcptr, 0); | ||
325 | |||
326 | W16(ep, fen_mflr, PKT_MAXBUF_SIZE); /* maximum frame length register */ | ||
327 | W16(ep, fen_minflr, PKT_MINBUF_SIZE); /* minimum frame length register */ | ||
328 | |||
329 | /* set address */ | ||
330 | mac = dev->dev_addr; | ||
331 | paddrh = ((u16)mac[5] << 8) | mac[4]; | ||
332 | paddrm = ((u16)mac[3] << 8) | mac[2]; | ||
333 | paddrl = ((u16)mac[1] << 8) | mac[0]; | ||
334 | |||
335 | W16(ep, fen_paddrh, paddrh); | ||
336 | W16(ep, fen_paddrm, paddrm); | ||
337 | W16(ep, fen_paddrl, paddrl); | ||
338 | |||
339 | W16(ep, fen_taddrh, 0); | ||
340 | W16(ep, fen_taddrm, 0); | ||
341 | W16(ep, fen_taddrl, 0); | ||
342 | |||
343 | W16(ep, fen_maxd1, 1520); /* maximum DMA1 length */ | ||
344 | W16(ep, fen_maxd2, 1520); /* maximum DMA2 length */ | ||
345 | |||
346 | /* Clear stat counters, in case we ever enable RMON */ | ||
347 | W32(ep, fen_octc, 0); | ||
348 | W32(ep, fen_colc, 0); | ||
349 | W32(ep, fen_broc, 0); | ||
350 | W32(ep, fen_mulc, 0); | ||
351 | W32(ep, fen_uspc, 0); | ||
352 | W32(ep, fen_frgc, 0); | ||
353 | W32(ep, fen_ospc, 0); | ||
354 | W32(ep, fen_jbrc, 0); | ||
355 | W32(ep, fen_p64c, 0); | ||
356 | W32(ep, fen_p65c, 0); | ||
357 | W32(ep, fen_p128c, 0); | ||
358 | W32(ep, fen_p256c, 0); | ||
359 | W32(ep, fen_p512c, 0); | ||
360 | W32(ep, fen_p1024c, 0); | ||
361 | |||
362 | W16(ep, fen_rfthr, 0); /* Suggested by manual */ | ||
363 | W16(ep, fen_rfcnt, 0); | ||
364 | W16(ep, fen_cftype, 0); | ||
365 | |||
366 | fs_init_bds(dev); | ||
367 | |||
368 | /* adjust to speed (for RMII mode) */ | ||
369 | if (fpi->use_rmii) { | ||
370 | if (fep->phydev->speed == 100) | ||
371 | C8(fcccp, fcc_gfemr, 0x20); | ||
372 | else | ||
373 | S8(fcccp, fcc_gfemr, 0x20); | ||
374 | } | ||
375 | |||
376 | fcc_cr_cmd(fep, CPM_CR_INIT_TRX); | ||
377 | |||
378 | /* clear events */ | ||
379 | W16(fccp, fcc_fcce, 0xffff); | ||
380 | |||
381 | /* Enable interrupts we wish to service */ | ||
382 | W16(fccp, fcc_fccm, FCC_ENET_TXE | FCC_ENET_RXF | FCC_ENET_TXB); | ||
383 | |||
384 | /* Set GFMR to enable Ethernet operating mode */ | ||
385 | W32(fccp, fcc_gfmr, FCC_GFMR_TCI | FCC_GFMR_MODE_ENET); | ||
386 | |||
387 | /* set sync/delimiters */ | ||
388 | W16(fccp, fcc_fdsr, 0xd555); | ||
389 | |||
390 | W32(fccp, fcc_fpsmr, FCC_PSMR_ENCRC); | ||
391 | |||
392 | if (fpi->use_rmii) | ||
393 | S32(fccp, fcc_fpsmr, FCC_PSMR_RMII); | ||
394 | |||
395 | /* adjust to duplex mode */ | ||
396 | if (fep->phydev->duplex) | ||
397 | S32(fccp, fcc_fpsmr, FCC_PSMR_FDE | FCC_PSMR_LPB); | ||
398 | else | ||
399 | C32(fccp, fcc_fpsmr, FCC_PSMR_FDE | FCC_PSMR_LPB); | ||
400 | |||
401 | /* Restore multicast and promiscuous settings */ | ||
402 | set_multicast_list(dev); | ||
403 | |||
404 | S32(fccp, fcc_gfmr, FCC_GFMR_ENR | FCC_GFMR_ENT); | ||
405 | } | ||
406 | |||
407 | static void stop(struct net_device *dev) | ||
408 | { | ||
409 | struct fs_enet_private *fep = netdev_priv(dev); | ||
410 | fcc_t __iomem *fccp = fep->fcc.fccp; | ||
411 | |||
412 | /* stop ethernet */ | ||
413 | C32(fccp, fcc_gfmr, FCC_GFMR_ENR | FCC_GFMR_ENT); | ||
414 | |||
415 | /* clear events */ | ||
416 | W16(fccp, fcc_fcce, 0xffff); | ||
417 | |||
418 | /* clear interrupt mask */ | ||
419 | W16(fccp, fcc_fccm, 0); | ||
420 | |||
421 | fs_cleanup_bds(dev); | ||
422 | } | ||
423 | |||
424 | static void napi_clear_rx_event(struct net_device *dev) | ||
425 | { | ||
426 | struct fs_enet_private *fep = netdev_priv(dev); | ||
427 | fcc_t __iomem *fccp = fep->fcc.fccp; | ||
428 | |||
429 | W16(fccp, fcc_fcce, FCC_NAPI_RX_EVENT_MSK); | ||
430 | } | ||
431 | |||
432 | static void napi_enable_rx(struct net_device *dev) | ||
433 | { | ||
434 | struct fs_enet_private *fep = netdev_priv(dev); | ||
435 | fcc_t __iomem *fccp = fep->fcc.fccp; | ||
436 | |||
437 | S16(fccp, fcc_fccm, FCC_NAPI_RX_EVENT_MSK); | ||
438 | } | ||
439 | |||
440 | static void napi_disable_rx(struct net_device *dev) | ||
441 | { | ||
442 | struct fs_enet_private *fep = netdev_priv(dev); | ||
443 | fcc_t __iomem *fccp = fep->fcc.fccp; | ||
444 | |||
445 | C16(fccp, fcc_fccm, FCC_NAPI_RX_EVENT_MSK); | ||
446 | } | ||
447 | |||
448 | static void rx_bd_done(struct net_device *dev) | ||
449 | { | ||
450 | /* nothing */ | ||
451 | } | ||
452 | |||
453 | static void tx_kickstart(struct net_device *dev) | ||
454 | { | ||
455 | struct fs_enet_private *fep = netdev_priv(dev); | ||
456 | fcc_t __iomem *fccp = fep->fcc.fccp; | ||
457 | |||
458 | S16(fccp, fcc_ftodr, 0x8000); | ||
459 | } | ||
460 | |||
461 | static u32 get_int_events(struct net_device *dev) | ||
462 | { | ||
463 | struct fs_enet_private *fep = netdev_priv(dev); | ||
464 | fcc_t __iomem *fccp = fep->fcc.fccp; | ||
465 | |||
466 | return (u32)R16(fccp, fcc_fcce); | ||
467 | } | ||
468 | |||
469 | static void clear_int_events(struct net_device *dev, u32 int_events) | ||
470 | { | ||
471 | struct fs_enet_private *fep = netdev_priv(dev); | ||
472 | fcc_t __iomem *fccp = fep->fcc.fccp; | ||
473 | |||
474 | W16(fccp, fcc_fcce, int_events & 0xffff); | ||
475 | } | ||
476 | |||
477 | static void ev_error(struct net_device *dev, u32 int_events) | ||
478 | { | ||
479 | struct fs_enet_private *fep = netdev_priv(dev); | ||
480 | |||
481 | dev_warn(fep->dev, "FS_ENET ERROR(s) 0x%x\n", int_events); | ||
482 | } | ||
483 | |||
484 | static int get_regs(struct net_device *dev, void *p, int *sizep) | ||
485 | { | ||
486 | struct fs_enet_private *fep = netdev_priv(dev); | ||
487 | |||
488 | if (*sizep < sizeof(fcc_t) + sizeof(fcc_enet_t) + 1) | ||
489 | return -EINVAL; | ||
490 | |||
491 | memcpy_fromio(p, fep->fcc.fccp, sizeof(fcc_t)); | ||
492 | p = (char *)p + sizeof(fcc_t); | ||
493 | |||
494 | memcpy_fromio(p, fep->fcc.ep, sizeof(fcc_enet_t)); | ||
495 | p = (char *)p + sizeof(fcc_enet_t); | ||
496 | |||
497 | memcpy_fromio(p, fep->fcc.fcccp, 1); | ||
498 | return 0; | ||
499 | } | ||
500 | |||
501 | static int get_regs_len(struct net_device *dev) | ||
502 | { | ||
503 | return sizeof(fcc_t) + sizeof(fcc_enet_t) + 1; | ||
504 | } | ||
505 | |||
506 | /* Some transmit errors cause the transmitter to shut | ||
507 | * down. We now issue a restart transmit. | ||
508 | * Also, to workaround 8260 device erratum CPM37, we must | ||
509 | * disable and then re-enable the transmitterfollowing a | ||
510 | * Late Collision, Underrun, or Retry Limit error. | ||
511 | * In addition, tbptr may point beyond BDs beyond still marked | ||
512 | * as ready due to internal pipelining, so we need to look back | ||
513 | * through the BDs and adjust tbptr to point to the last BD | ||
514 | * marked as ready. This may result in some buffers being | ||
515 | * retransmitted. | ||
516 | */ | ||
517 | static void tx_restart(struct net_device *dev) | ||
518 | { | ||
519 | struct fs_enet_private *fep = netdev_priv(dev); | ||
520 | fcc_t __iomem *fccp = fep->fcc.fccp; | ||
521 | const struct fs_platform_info *fpi = fep->fpi; | ||
522 | fcc_enet_t __iomem *ep = fep->fcc.ep; | ||
523 | cbd_t __iomem *curr_tbptr; | ||
524 | cbd_t __iomem *recheck_bd; | ||
525 | cbd_t __iomem *prev_bd; | ||
526 | cbd_t __iomem *last_tx_bd; | ||
527 | |||
528 | last_tx_bd = fep->tx_bd_base + (fpi->tx_ring * sizeof(cbd_t)); | ||
529 | |||
530 | /* get the current bd held in TBPTR and scan back from this point */ | ||
531 | recheck_bd = curr_tbptr = (cbd_t __iomem *) | ||
532 | ((R32(ep, fen_genfcc.fcc_tbptr) - fep->ring_mem_addr) + | ||
533 | fep->ring_base); | ||
534 | |||
535 | prev_bd = (recheck_bd == fep->tx_bd_base) ? last_tx_bd : recheck_bd - 1; | ||
536 | |||
537 | /* Move through the bds in reverse, look for the earliest buffer | ||
538 | * that is not ready. Adjust TBPTR to the following buffer */ | ||
539 | while ((CBDR_SC(prev_bd) & BD_ENET_TX_READY) != 0) { | ||
540 | /* Go back one buffer */ | ||
541 | recheck_bd = prev_bd; | ||
542 | |||
543 | /* update the previous buffer */ | ||
544 | prev_bd = (prev_bd == fep->tx_bd_base) ? last_tx_bd : prev_bd - 1; | ||
545 | |||
546 | /* We should never see all bds marked as ready, check anyway */ | ||
547 | if (recheck_bd == curr_tbptr) | ||
548 | break; | ||
549 | } | ||
550 | /* Now update the TBPTR and dirty flag to the current buffer */ | ||
551 | W32(ep, fen_genfcc.fcc_tbptr, | ||
552 | (uint) (((void *)recheck_bd - fep->ring_base) + | ||
553 | fep->ring_mem_addr)); | ||
554 | fep->dirty_tx = recheck_bd; | ||
555 | |||
556 | C32(fccp, fcc_gfmr, FCC_GFMR_ENT); | ||
557 | udelay(10); | ||
558 | S32(fccp, fcc_gfmr, FCC_GFMR_ENT); | ||
559 | |||
560 | fcc_cr_cmd(fep, CPM_CR_RESTART_TX); | ||
561 | } | ||
562 | |||
563 | /*************************************************************************/ | ||
564 | |||
565 | const struct fs_ops fs_fcc_ops = { | ||
566 | .setup_data = setup_data, | ||
567 | .cleanup_data = cleanup_data, | ||
568 | .set_multicast_list = set_multicast_list, | ||
569 | .restart = restart, | ||
570 | .stop = stop, | ||
571 | .napi_clear_rx_event = napi_clear_rx_event, | ||
572 | .napi_enable_rx = napi_enable_rx, | ||
573 | .napi_disable_rx = napi_disable_rx, | ||
574 | .rx_bd_done = rx_bd_done, | ||
575 | .tx_kickstart = tx_kickstart, | ||
576 | .get_int_events = get_int_events, | ||
577 | .clear_int_events = clear_int_events, | ||
578 | .ev_error = ev_error, | ||
579 | .get_regs = get_regs, | ||
580 | .get_regs_len = get_regs_len, | ||
581 | .tx_restart = tx_restart, | ||
582 | .allocate_bd = allocate_bd, | ||
583 | .free_bd = free_bd, | ||
584 | }; | ||
diff --git a/drivers/net/fs_enet/mac-fec.c b/drivers/net/fs_enet/mac-fec.c new file mode 100644 index 00000000000..b9fbc83d64a --- /dev/null +++ b/drivers/net/fs_enet/mac-fec.c | |||
@@ -0,0 +1,498 @@ | |||
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/module.h> | ||
16 | #include <linux/kernel.h> | ||
17 | #include <linux/types.h> | ||
18 | #include <linux/string.h> | ||
19 | #include <linux/ptrace.h> | ||
20 | #include <linux/errno.h> | ||
21 | #include <linux/ioport.h> | ||
22 | #include <linux/interrupt.h> | ||
23 | #include <linux/init.h> | ||
24 | #include <linux/delay.h> | ||
25 | #include <linux/netdevice.h> | ||
26 | #include <linux/etherdevice.h> | ||
27 | #include <linux/skbuff.h> | ||
28 | #include <linux/spinlock.h> | ||
29 | #include <linux/mii.h> | ||
30 | #include <linux/ethtool.h> | ||
31 | #include <linux/bitops.h> | ||
32 | #include <linux/fs.h> | ||
33 | #include <linux/platform_device.h> | ||
34 | #include <linux/of_device.h> | ||
35 | #include <linux/gfp.h> | ||
36 | |||
37 | #include <asm/irq.h> | ||
38 | #include <asm/uaccess.h> | ||
39 | |||
40 | #ifdef CONFIG_8xx | ||
41 | #include <asm/8xx_immap.h> | ||
42 | #include <asm/pgtable.h> | ||
43 | #include <asm/mpc8xx.h> | ||
44 | #include <asm/cpm1.h> | ||
45 | #endif | ||
46 | |||
47 | #include "fs_enet.h" | ||
48 | #include "fec.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 | * Delay to wait for FEC reset command to complete (in us) | ||
80 | */ | ||
81 | #define FEC_RESET_DELAY 50 | ||
82 | |||
83 | static int whack_reset(struct fec __iomem *fecp) | ||
84 | { | ||
85 | int i; | ||
86 | |||
87 | FW(fecp, ecntrl, FEC_ECNTRL_PINMUX | FEC_ECNTRL_RESET); | ||
88 | for (i = 0; i < FEC_RESET_DELAY; i++) { | ||
89 | if ((FR(fecp, ecntrl) & FEC_ECNTRL_RESET) == 0) | ||
90 | return 0; /* OK */ | ||
91 | udelay(1); | ||
92 | } | ||
93 | |||
94 | return -1; | ||
95 | } | ||
96 | |||
97 | static int do_pd_setup(struct fs_enet_private *fep) | ||
98 | { | ||
99 | struct platform_device *ofdev = to_platform_device(fep->dev); | ||
100 | |||
101 | fep->interrupt = of_irq_to_resource(ofdev->dev.of_node, 0, NULL); | ||
102 | if (fep->interrupt == NO_IRQ) | ||
103 | return -EINVAL; | ||
104 | |||
105 | fep->fec.fecp = of_iomap(ofdev->dev.of_node, 0); | ||
106 | if (!fep->fcc.fccp) | ||
107 | return -EINVAL; | ||
108 | |||
109 | return 0; | ||
110 | } | ||
111 | |||
112 | #define FEC_NAPI_RX_EVENT_MSK (FEC_ENET_RXF | FEC_ENET_RXB) | ||
113 | #define FEC_RX_EVENT (FEC_ENET_RXF) | ||
114 | #define FEC_TX_EVENT (FEC_ENET_TXF) | ||
115 | #define FEC_ERR_EVENT_MSK (FEC_ENET_HBERR | FEC_ENET_BABR | \ | ||
116 | FEC_ENET_BABT | FEC_ENET_EBERR) | ||
117 | |||
118 | static int setup_data(struct net_device *dev) | ||
119 | { | ||
120 | struct fs_enet_private *fep = netdev_priv(dev); | ||
121 | |||
122 | if (do_pd_setup(fep) != 0) | ||
123 | return -EINVAL; | ||
124 | |||
125 | fep->fec.hthi = 0; | ||
126 | fep->fec.htlo = 0; | ||
127 | |||
128 | fep->ev_napi_rx = FEC_NAPI_RX_EVENT_MSK; | ||
129 | fep->ev_rx = FEC_RX_EVENT; | ||
130 | fep->ev_tx = FEC_TX_EVENT; | ||
131 | fep->ev_err = FEC_ERR_EVENT_MSK; | ||
132 | |||
133 | return 0; | ||
134 | } | ||
135 | |||
136 | static int allocate_bd(struct net_device *dev) | ||
137 | { | ||
138 | struct fs_enet_private *fep = netdev_priv(dev); | ||
139 | const struct fs_platform_info *fpi = fep->fpi; | ||
140 | |||
141 | fep->ring_base = (void __force __iomem *)dma_alloc_coherent(fep->dev, | ||
142 | (fpi->tx_ring + fpi->rx_ring) * | ||
143 | sizeof(cbd_t), &fep->ring_mem_addr, | ||
144 | GFP_KERNEL); | ||
145 | if (fep->ring_base == NULL) | ||
146 | return -ENOMEM; | ||
147 | |||
148 | return 0; | ||
149 | } | ||
150 | |||
151 | static void free_bd(struct net_device *dev) | ||
152 | { | ||
153 | struct fs_enet_private *fep = netdev_priv(dev); | ||
154 | const struct fs_platform_info *fpi = fep->fpi; | ||
155 | |||
156 | if(fep->ring_base) | ||
157 | dma_free_coherent(fep->dev, (fpi->tx_ring + fpi->rx_ring) | ||
158 | * sizeof(cbd_t), | ||
159 | (void __force *)fep->ring_base, | ||
160 | fep->ring_mem_addr); | ||
161 | } | ||
162 | |||
163 | static void cleanup_data(struct net_device *dev) | ||
164 | { | ||
165 | /* nothing */ | ||
166 | } | ||
167 | |||
168 | static void set_promiscuous_mode(struct net_device *dev) | ||
169 | { | ||
170 | struct fs_enet_private *fep = netdev_priv(dev); | ||
171 | struct fec __iomem *fecp = fep->fec.fecp; | ||
172 | |||
173 | FS(fecp, r_cntrl, FEC_RCNTRL_PROM); | ||
174 | } | ||
175 | |||
176 | static void set_multicast_start(struct net_device *dev) | ||
177 | { | ||
178 | struct fs_enet_private *fep = netdev_priv(dev); | ||
179 | |||
180 | fep->fec.hthi = 0; | ||
181 | fep->fec.htlo = 0; | ||
182 | } | ||
183 | |||
184 | static void set_multicast_one(struct net_device *dev, const u8 *mac) | ||
185 | { | ||
186 | struct fs_enet_private *fep = netdev_priv(dev); | ||
187 | int temp, hash_index, i, j; | ||
188 | u32 crc, csrVal; | ||
189 | u8 byte, msb; | ||
190 | |||
191 | crc = 0xffffffff; | ||
192 | for (i = 0; i < 6; i++) { | ||
193 | byte = mac[i]; | ||
194 | for (j = 0; j < 8; j++) { | ||
195 | msb = crc >> 31; | ||
196 | crc <<= 1; | ||
197 | if (msb ^ (byte & 0x1)) | ||
198 | crc ^= FEC_CRC_POLY; | ||
199 | byte >>= 1; | ||
200 | } | ||
201 | } | ||
202 | |||
203 | temp = (crc & 0x3f) >> 1; | ||
204 | hash_index = ((temp & 0x01) << 4) | | ||
205 | ((temp & 0x02) << 2) | | ||
206 | ((temp & 0x04)) | | ||
207 | ((temp & 0x08) >> 2) | | ||
208 | ((temp & 0x10) >> 4); | ||
209 | csrVal = 1 << hash_index; | ||
210 | if (crc & 1) | ||
211 | fep->fec.hthi |= csrVal; | ||
212 | else | ||
213 | fep->fec.htlo |= csrVal; | ||
214 | } | ||
215 | |||
216 | static void set_multicast_finish(struct net_device *dev) | ||
217 | { | ||
218 | struct fs_enet_private *fep = netdev_priv(dev); | ||
219 | struct fec __iomem *fecp = fep->fec.fecp; | ||
220 | |||
221 | /* if all multi or too many multicasts; just enable all */ | ||
222 | if ((dev->flags & IFF_ALLMULTI) != 0 || | ||
223 | netdev_mc_count(dev) > FEC_MAX_MULTICAST_ADDRS) { | ||
224 | fep->fec.hthi = 0xffffffffU; | ||
225 | fep->fec.htlo = 0xffffffffU; | ||
226 | } | ||
227 | |||
228 | FC(fecp, r_cntrl, FEC_RCNTRL_PROM); | ||
229 | FW(fecp, grp_hash_table_high, fep->fec.hthi); | ||
230 | FW(fecp, grp_hash_table_low, fep->fec.htlo); | ||
231 | } | ||
232 | |||
233 | static void set_multicast_list(struct net_device *dev) | ||
234 | { | ||
235 | struct netdev_hw_addr *ha; | ||
236 | |||
237 | if ((dev->flags & IFF_PROMISC) == 0) { | ||
238 | set_multicast_start(dev); | ||
239 | netdev_for_each_mc_addr(ha, dev) | ||
240 | set_multicast_one(dev, ha->addr); | ||
241 | set_multicast_finish(dev); | ||
242 | } else | ||
243 | set_promiscuous_mode(dev); | ||
244 | } | ||
245 | |||
246 | static void restart(struct net_device *dev) | ||
247 | { | ||
248 | struct fs_enet_private *fep = netdev_priv(dev); | ||
249 | struct fec __iomem *fecp = fep->fec.fecp; | ||
250 | const struct fs_platform_info *fpi = fep->fpi; | ||
251 | dma_addr_t rx_bd_base_phys, tx_bd_base_phys; | ||
252 | int r; | ||
253 | u32 addrhi, addrlo; | ||
254 | |||
255 | struct mii_bus* mii = fep->phydev->bus; | ||
256 | struct fec_info* fec_inf = mii->priv; | ||
257 | |||
258 | r = whack_reset(fep->fec.fecp); | ||
259 | if (r != 0) | ||
260 | dev_err(fep->dev, "FEC Reset FAILED!\n"); | ||
261 | /* | ||
262 | * Set station address. | ||
263 | */ | ||
264 | addrhi = ((u32) dev->dev_addr[0] << 24) | | ||
265 | ((u32) dev->dev_addr[1] << 16) | | ||
266 | ((u32) dev->dev_addr[2] << 8) | | ||
267 | (u32) dev->dev_addr[3]; | ||
268 | addrlo = ((u32) dev->dev_addr[4] << 24) | | ||
269 | ((u32) dev->dev_addr[5] << 16); | ||
270 | FW(fecp, addr_low, addrhi); | ||
271 | FW(fecp, addr_high, addrlo); | ||
272 | |||
273 | /* | ||
274 | * Reset all multicast. | ||
275 | */ | ||
276 | FW(fecp, grp_hash_table_high, fep->fec.hthi); | ||
277 | FW(fecp, grp_hash_table_low, fep->fec.htlo); | ||
278 | |||
279 | /* | ||
280 | * Set maximum receive buffer size. | ||
281 | */ | ||
282 | FW(fecp, r_buff_size, PKT_MAXBLR_SIZE); | ||
283 | #ifdef CONFIG_FS_ENET_MPC5121_FEC | ||
284 | FW(fecp, r_cntrl, PKT_MAXBUF_SIZE << 16); | ||
285 | #else | ||
286 | FW(fecp, r_hash, PKT_MAXBUF_SIZE); | ||
287 | #endif | ||
288 | |||
289 | /* get physical address */ | ||
290 | rx_bd_base_phys = fep->ring_mem_addr; | ||
291 | tx_bd_base_phys = rx_bd_base_phys + sizeof(cbd_t) * fpi->rx_ring; | ||
292 | |||
293 | /* | ||
294 | * Set receive and transmit descriptor base. | ||
295 | */ | ||
296 | FW(fecp, r_des_start, rx_bd_base_phys); | ||
297 | FW(fecp, x_des_start, tx_bd_base_phys); | ||
298 | |||
299 | fs_init_bds(dev); | ||
300 | |||
301 | /* | ||
302 | * Enable big endian and don't care about SDMA FC. | ||
303 | */ | ||
304 | #ifdef CONFIG_FS_ENET_MPC5121_FEC | ||
305 | FS(fecp, dma_control, 0xC0000000); | ||
306 | #else | ||
307 | FW(fecp, fun_code, 0x78000000); | ||
308 | #endif | ||
309 | |||
310 | /* | ||
311 | * Set MII speed. | ||
312 | */ | ||
313 | FW(fecp, mii_speed, fec_inf->mii_speed); | ||
314 | |||
315 | /* | ||
316 | * Clear any outstanding interrupt. | ||
317 | */ | ||
318 | FW(fecp, ievent, 0xffc0); | ||
319 | #ifndef CONFIG_FS_ENET_MPC5121_FEC | ||
320 | FW(fecp, ivec, (virq_to_hw(fep->interrupt) / 2) << 29); | ||
321 | |||
322 | FW(fecp, r_cntrl, FEC_RCNTRL_MII_MODE); /* MII enable */ | ||
323 | #else | ||
324 | /* | ||
325 | * Only set MII mode - do not touch maximum frame length | ||
326 | * configured before. | ||
327 | */ | ||
328 | FS(fecp, r_cntrl, FEC_RCNTRL_MII_MODE); | ||
329 | #endif | ||
330 | /* | ||
331 | * adjust to duplex mode | ||
332 | */ | ||
333 | if (fep->phydev->duplex) { | ||
334 | FC(fecp, r_cntrl, FEC_RCNTRL_DRT); | ||
335 | FS(fecp, x_cntrl, FEC_TCNTRL_FDEN); /* FD enable */ | ||
336 | } else { | ||
337 | FS(fecp, r_cntrl, FEC_RCNTRL_DRT); | ||
338 | FC(fecp, x_cntrl, FEC_TCNTRL_FDEN); /* FD disable */ | ||
339 | } | ||
340 | |||
341 | /* | ||
342 | * Enable interrupts we wish to service. | ||
343 | */ | ||
344 | FW(fecp, imask, FEC_ENET_TXF | FEC_ENET_TXB | | ||
345 | FEC_ENET_RXF | FEC_ENET_RXB); | ||
346 | |||
347 | /* | ||
348 | * And last, enable the transmit and receive processing. | ||
349 | */ | ||
350 | FW(fecp, ecntrl, FEC_ECNTRL_PINMUX | FEC_ECNTRL_ETHER_EN); | ||
351 | FW(fecp, r_des_active, 0x01000000); | ||
352 | } | ||
353 | |||
354 | static void stop(struct net_device *dev) | ||
355 | { | ||
356 | struct fs_enet_private *fep = netdev_priv(dev); | ||
357 | const struct fs_platform_info *fpi = fep->fpi; | ||
358 | struct fec __iomem *fecp = fep->fec.fecp; | ||
359 | |||
360 | struct fec_info* feci= fep->phydev->bus->priv; | ||
361 | |||
362 | int i; | ||
363 | |||
364 | if ((FR(fecp, ecntrl) & FEC_ECNTRL_ETHER_EN) == 0) | ||
365 | return; /* already down */ | ||
366 | |||
367 | FW(fecp, x_cntrl, 0x01); /* Graceful transmit stop */ | ||
368 | for (i = 0; ((FR(fecp, ievent) & 0x10000000) == 0) && | ||
369 | i < FEC_RESET_DELAY; i++) | ||
370 | udelay(1); | ||
371 | |||
372 | if (i == FEC_RESET_DELAY) | ||
373 | dev_warn(fep->dev, "FEC timeout on graceful transmit stop\n"); | ||
374 | /* | ||
375 | * Disable FEC. Let only MII interrupts. | ||
376 | */ | ||
377 | FW(fecp, imask, 0); | ||
378 | FC(fecp, ecntrl, FEC_ECNTRL_ETHER_EN); | ||
379 | |||
380 | fs_cleanup_bds(dev); | ||
381 | |||
382 | /* shut down FEC1? that's where the mii bus is */ | ||
383 | if (fpi->has_phy) { | ||
384 | FS(fecp, r_cntrl, FEC_RCNTRL_MII_MODE); /* MII enable */ | ||
385 | FS(fecp, ecntrl, FEC_ECNTRL_PINMUX | FEC_ECNTRL_ETHER_EN); | ||
386 | FW(fecp, ievent, FEC_ENET_MII); | ||
387 | FW(fecp, mii_speed, feci->mii_speed); | ||
388 | } | ||
389 | } | ||
390 | |||
391 | static void napi_clear_rx_event(struct net_device *dev) | ||
392 | { | ||
393 | struct fs_enet_private *fep = netdev_priv(dev); | ||
394 | struct fec __iomem *fecp = fep->fec.fecp; | ||
395 | |||
396 | FW(fecp, ievent, FEC_NAPI_RX_EVENT_MSK); | ||
397 | } | ||
398 | |||
399 | static void napi_enable_rx(struct net_device *dev) | ||
400 | { | ||
401 | struct fs_enet_private *fep = netdev_priv(dev); | ||
402 | struct fec __iomem *fecp = fep->fec.fecp; | ||
403 | |||
404 | FS(fecp, imask, FEC_NAPI_RX_EVENT_MSK); | ||
405 | } | ||
406 | |||
407 | static void napi_disable_rx(struct net_device *dev) | ||
408 | { | ||
409 | struct fs_enet_private *fep = netdev_priv(dev); | ||
410 | struct fec __iomem *fecp = fep->fec.fecp; | ||
411 | |||
412 | FC(fecp, imask, FEC_NAPI_RX_EVENT_MSK); | ||
413 | } | ||
414 | |||
415 | static void rx_bd_done(struct net_device *dev) | ||
416 | { | ||
417 | struct fs_enet_private *fep = netdev_priv(dev); | ||
418 | struct fec __iomem *fecp = fep->fec.fecp; | ||
419 | |||
420 | FW(fecp, r_des_active, 0x01000000); | ||
421 | } | ||
422 | |||
423 | static void tx_kickstart(struct net_device *dev) | ||
424 | { | ||
425 | struct fs_enet_private *fep = netdev_priv(dev); | ||
426 | struct fec __iomem *fecp = fep->fec.fecp; | ||
427 | |||
428 | FW(fecp, x_des_active, 0x01000000); | ||
429 | } | ||
430 | |||
431 | static u32 get_int_events(struct net_device *dev) | ||
432 | { | ||
433 | struct fs_enet_private *fep = netdev_priv(dev); | ||
434 | struct fec __iomem *fecp = fep->fec.fecp; | ||
435 | |||
436 | return FR(fecp, ievent) & FR(fecp, imask); | ||
437 | } | ||
438 | |||
439 | static void clear_int_events(struct net_device *dev, u32 int_events) | ||
440 | { | ||
441 | struct fs_enet_private *fep = netdev_priv(dev); | ||
442 | struct fec __iomem *fecp = fep->fec.fecp; | ||
443 | |||
444 | FW(fecp, ievent, int_events); | ||
445 | } | ||
446 | |||
447 | static void ev_error(struct net_device *dev, u32 int_events) | ||
448 | { | ||
449 | struct fs_enet_private *fep = netdev_priv(dev); | ||
450 | |||
451 | dev_warn(fep->dev, "FEC ERROR(s) 0x%x\n", int_events); | ||
452 | } | ||
453 | |||
454 | static int get_regs(struct net_device *dev, void *p, int *sizep) | ||
455 | { | ||
456 | struct fs_enet_private *fep = netdev_priv(dev); | ||
457 | |||
458 | if (*sizep < sizeof(struct fec)) | ||
459 | return -EINVAL; | ||
460 | |||
461 | memcpy_fromio(p, fep->fec.fecp, sizeof(struct fec)); | ||
462 | |||
463 | return 0; | ||
464 | } | ||
465 | |||
466 | static int get_regs_len(struct net_device *dev) | ||
467 | { | ||
468 | return sizeof(struct fec); | ||
469 | } | ||
470 | |||
471 | static void tx_restart(struct net_device *dev) | ||
472 | { | ||
473 | /* nothing */ | ||
474 | } | ||
475 | |||
476 | /*************************************************************************/ | ||
477 | |||
478 | const struct fs_ops fs_fec_ops = { | ||
479 | .setup_data = setup_data, | ||
480 | .cleanup_data = cleanup_data, | ||
481 | .set_multicast_list = set_multicast_list, | ||
482 | .restart = restart, | ||
483 | .stop = stop, | ||
484 | .napi_clear_rx_event = napi_clear_rx_event, | ||
485 | .napi_enable_rx = napi_enable_rx, | ||
486 | .napi_disable_rx = napi_disable_rx, | ||
487 | .rx_bd_done = rx_bd_done, | ||
488 | .tx_kickstart = tx_kickstart, | ||
489 | .get_int_events = get_int_events, | ||
490 | .clear_int_events = clear_int_events, | ||
491 | .ev_error = ev_error, | ||
492 | .get_regs = get_regs, | ||
493 | .get_regs_len = get_regs_len, | ||
494 | .tx_restart = tx_restart, | ||
495 | .allocate_bd = allocate_bd, | ||
496 | .free_bd = free_bd, | ||
497 | }; | ||
498 | |||
diff --git a/drivers/net/fs_enet/mac-scc.c b/drivers/net/fs_enet/mac-scc.c new file mode 100644 index 00000000000..22a02a76706 --- /dev/null +++ b/drivers/net/fs_enet/mac-scc.c | |||
@@ -0,0 +1,484 @@ | |||
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/module.h> | ||
16 | #include <linux/kernel.h> | ||
17 | #include <linux/types.h> | ||
18 | #include <linux/string.h> | ||
19 | #include <linux/ptrace.h> | ||
20 | #include <linux/errno.h> | ||
21 | #include <linux/ioport.h> | ||
22 | #include <linux/interrupt.h> | ||
23 | #include <linux/init.h> | ||
24 | #include <linux/delay.h> | ||
25 | #include <linux/netdevice.h> | ||
26 | #include <linux/etherdevice.h> | ||
27 | #include <linux/skbuff.h> | ||
28 | #include <linux/spinlock.h> | ||
29 | #include <linux/mii.h> | ||
30 | #include <linux/ethtool.h> | ||
31 | #include <linux/bitops.h> | ||
32 | #include <linux/fs.h> | ||
33 | #include <linux/platform_device.h> | ||
34 | #include <linux/of_platform.h> | ||
35 | |||
36 | #include <asm/irq.h> | ||
37 | #include <asm/uaccess.h> | ||
38 | |||
39 | #ifdef CONFIG_8xx | ||
40 | #include <asm/8xx_immap.h> | ||
41 | #include <asm/pgtable.h> | ||
42 | #include <asm/mpc8xx.h> | ||
43 | #include <asm/cpm1.h> | ||
44 | #endif | ||
45 | |||
46 | #include "fs_enet.h" | ||
47 | |||
48 | /*************************************************/ | ||
49 | #if defined(CONFIG_CPM1) | ||
50 | /* for a 8xx __raw_xxx's are sufficient */ | ||
51 | #define __fs_out32(addr, x) __raw_writel(x, addr) | ||
52 | #define __fs_out16(addr, x) __raw_writew(x, addr) | ||
53 | #define __fs_out8(addr, x) __raw_writeb(x, addr) | ||
54 | #define __fs_in32(addr) __raw_readl(addr) | ||
55 | #define __fs_in16(addr) __raw_readw(addr) | ||
56 | #define __fs_in8(addr) __raw_readb(addr) | ||
57 | #else | ||
58 | /* for others play it safe */ | ||
59 | #define __fs_out32(addr, x) out_be32(addr, x) | ||
60 | #define __fs_out16(addr, x) out_be16(addr, x) | ||
61 | #define __fs_in32(addr) in_be32(addr) | ||
62 | #define __fs_in16(addr) in_be16(addr) | ||
63 | #define __fs_out8(addr, x) out_8(addr, x) | ||
64 | #define __fs_in8(addr) in_8(addr) | ||
65 | #endif | ||
66 | |||
67 | /* write, read, set bits, clear bits */ | ||
68 | #define W32(_p, _m, _v) __fs_out32(&(_p)->_m, (_v)) | ||
69 | #define R32(_p, _m) __fs_in32(&(_p)->_m) | ||
70 | #define S32(_p, _m, _v) W32(_p, _m, R32(_p, _m) | (_v)) | ||
71 | #define C32(_p, _m, _v) W32(_p, _m, R32(_p, _m) & ~(_v)) | ||
72 | |||
73 | #define W16(_p, _m, _v) __fs_out16(&(_p)->_m, (_v)) | ||
74 | #define R16(_p, _m) __fs_in16(&(_p)->_m) | ||
75 | #define S16(_p, _m, _v) W16(_p, _m, R16(_p, _m) | (_v)) | ||
76 | #define C16(_p, _m, _v) W16(_p, _m, R16(_p, _m) & ~(_v)) | ||
77 | |||
78 | #define W8(_p, _m, _v) __fs_out8(&(_p)->_m, (_v)) | ||
79 | #define R8(_p, _m) __fs_in8(&(_p)->_m) | ||
80 | #define S8(_p, _m, _v) W8(_p, _m, R8(_p, _m) | (_v)) | ||
81 | #define C8(_p, _m, _v) W8(_p, _m, R8(_p, _m) & ~(_v)) | ||
82 | |||
83 | #define SCC_MAX_MULTICAST_ADDRS 64 | ||
84 | |||
85 | /* | ||
86 | * Delay to wait for SCC reset command to complete (in us) | ||
87 | */ | ||
88 | #define SCC_RESET_DELAY 50 | ||
89 | |||
90 | static inline int scc_cr_cmd(struct fs_enet_private *fep, u32 op) | ||
91 | { | ||
92 | const struct fs_platform_info *fpi = fep->fpi; | ||
93 | |||
94 | return cpm_command(fpi->cp_command, op); | ||
95 | } | ||
96 | |||
97 | static int do_pd_setup(struct fs_enet_private *fep) | ||
98 | { | ||
99 | struct platform_device *ofdev = to_platform_device(fep->dev); | ||
100 | |||
101 | fep->interrupt = of_irq_to_resource(ofdev->dev.of_node, 0, NULL); | ||
102 | if (fep->interrupt == NO_IRQ) | ||
103 | return -EINVAL; | ||
104 | |||
105 | fep->scc.sccp = of_iomap(ofdev->dev.of_node, 0); | ||
106 | if (!fep->scc.sccp) | ||
107 | return -EINVAL; | ||
108 | |||
109 | fep->scc.ep = of_iomap(ofdev->dev.of_node, 1); | ||
110 | if (!fep->scc.ep) { | ||
111 | iounmap(fep->scc.sccp); | ||
112 | return -EINVAL; | ||
113 | } | ||
114 | |||
115 | return 0; | ||
116 | } | ||
117 | |||
118 | #define SCC_NAPI_RX_EVENT_MSK (SCCE_ENET_RXF | SCCE_ENET_RXB) | ||
119 | #define SCC_RX_EVENT (SCCE_ENET_RXF) | ||
120 | #define SCC_TX_EVENT (SCCE_ENET_TXB) | ||
121 | #define SCC_ERR_EVENT_MSK (SCCE_ENET_TXE | SCCE_ENET_BSY) | ||
122 | |||
123 | static int setup_data(struct net_device *dev) | ||
124 | { | ||
125 | struct fs_enet_private *fep = netdev_priv(dev); | ||
126 | |||
127 | do_pd_setup(fep); | ||
128 | |||
129 | fep->scc.hthi = 0; | ||
130 | fep->scc.htlo = 0; | ||
131 | |||
132 | fep->ev_napi_rx = SCC_NAPI_RX_EVENT_MSK; | ||
133 | fep->ev_rx = SCC_RX_EVENT; | ||
134 | fep->ev_tx = SCC_TX_EVENT | SCCE_ENET_TXE; | ||
135 | fep->ev_err = SCC_ERR_EVENT_MSK; | ||
136 | |||
137 | return 0; | ||
138 | } | ||
139 | |||
140 | static int allocate_bd(struct net_device *dev) | ||
141 | { | ||
142 | struct fs_enet_private *fep = netdev_priv(dev); | ||
143 | const struct fs_platform_info *fpi = fep->fpi; | ||
144 | |||
145 | fep->ring_mem_addr = cpm_dpalloc((fpi->tx_ring + fpi->rx_ring) * | ||
146 | sizeof(cbd_t), 8); | ||
147 | if (IS_ERR_VALUE(fep->ring_mem_addr)) | ||
148 | return -ENOMEM; | ||
149 | |||
150 | fep->ring_base = (void __iomem __force*) | ||
151 | cpm_dpram_addr(fep->ring_mem_addr); | ||
152 | |||
153 | return 0; | ||
154 | } | ||
155 | |||
156 | static void free_bd(struct net_device *dev) | ||
157 | { | ||
158 | struct fs_enet_private *fep = netdev_priv(dev); | ||
159 | |||
160 | if (fep->ring_base) | ||
161 | cpm_dpfree(fep->ring_mem_addr); | ||
162 | } | ||
163 | |||
164 | static void cleanup_data(struct net_device *dev) | ||
165 | { | ||
166 | /* nothing */ | ||
167 | } | ||
168 | |||
169 | static void set_promiscuous_mode(struct net_device *dev) | ||
170 | { | ||
171 | struct fs_enet_private *fep = netdev_priv(dev); | ||
172 | scc_t __iomem *sccp = fep->scc.sccp; | ||
173 | |||
174 | S16(sccp, scc_psmr, SCC_PSMR_PRO); | ||
175 | } | ||
176 | |||
177 | static void set_multicast_start(struct net_device *dev) | ||
178 | { | ||
179 | struct fs_enet_private *fep = netdev_priv(dev); | ||
180 | scc_enet_t __iomem *ep = fep->scc.ep; | ||
181 | |||
182 | W16(ep, sen_gaddr1, 0); | ||
183 | W16(ep, sen_gaddr2, 0); | ||
184 | W16(ep, sen_gaddr3, 0); | ||
185 | W16(ep, sen_gaddr4, 0); | ||
186 | } | ||
187 | |||
188 | static void set_multicast_one(struct net_device *dev, const u8 * mac) | ||
189 | { | ||
190 | struct fs_enet_private *fep = netdev_priv(dev); | ||
191 | scc_enet_t __iomem *ep = fep->scc.ep; | ||
192 | u16 taddrh, taddrm, taddrl; | ||
193 | |||
194 | taddrh = ((u16) mac[5] << 8) | mac[4]; | ||
195 | taddrm = ((u16) mac[3] << 8) | mac[2]; | ||
196 | taddrl = ((u16) mac[1] << 8) | mac[0]; | ||
197 | |||
198 | W16(ep, sen_taddrh, taddrh); | ||
199 | W16(ep, sen_taddrm, taddrm); | ||
200 | W16(ep, sen_taddrl, taddrl); | ||
201 | scc_cr_cmd(fep, CPM_CR_SET_GADDR); | ||
202 | } | ||
203 | |||
204 | static void set_multicast_finish(struct net_device *dev) | ||
205 | { | ||
206 | struct fs_enet_private *fep = netdev_priv(dev); | ||
207 | scc_t __iomem *sccp = fep->scc.sccp; | ||
208 | scc_enet_t __iomem *ep = fep->scc.ep; | ||
209 | |||
210 | /* clear promiscuous always */ | ||
211 | C16(sccp, scc_psmr, SCC_PSMR_PRO); | ||
212 | |||
213 | /* if all multi or too many multicasts; just enable all */ | ||
214 | if ((dev->flags & IFF_ALLMULTI) != 0 || | ||
215 | netdev_mc_count(dev) > SCC_MAX_MULTICAST_ADDRS) { | ||
216 | |||
217 | W16(ep, sen_gaddr1, 0xffff); | ||
218 | W16(ep, sen_gaddr2, 0xffff); | ||
219 | W16(ep, sen_gaddr3, 0xffff); | ||
220 | W16(ep, sen_gaddr4, 0xffff); | ||
221 | } | ||
222 | } | ||
223 | |||
224 | static void set_multicast_list(struct net_device *dev) | ||
225 | { | ||
226 | struct netdev_hw_addr *ha; | ||
227 | |||
228 | if ((dev->flags & IFF_PROMISC) == 0) { | ||
229 | set_multicast_start(dev); | ||
230 | netdev_for_each_mc_addr(ha, dev) | ||
231 | set_multicast_one(dev, ha->addr); | ||
232 | set_multicast_finish(dev); | ||
233 | } else | ||
234 | set_promiscuous_mode(dev); | ||
235 | } | ||
236 | |||
237 | /* | ||
238 | * This function is called to start or restart the FEC during a link | ||
239 | * change. This only happens when switching between half and full | ||
240 | * duplex. | ||
241 | */ | ||
242 | static void restart(struct net_device *dev) | ||
243 | { | ||
244 | struct fs_enet_private *fep = netdev_priv(dev); | ||
245 | scc_t __iomem *sccp = fep->scc.sccp; | ||
246 | scc_enet_t __iomem *ep = fep->scc.ep; | ||
247 | const struct fs_platform_info *fpi = fep->fpi; | ||
248 | u16 paddrh, paddrm, paddrl; | ||
249 | const unsigned char *mac; | ||
250 | int i; | ||
251 | |||
252 | C32(sccp, scc_gsmrl, SCC_GSMRL_ENR | SCC_GSMRL_ENT); | ||
253 | |||
254 | /* clear everything (slow & steady does it) */ | ||
255 | for (i = 0; i < sizeof(*ep); i++) | ||
256 | __fs_out8((u8 __iomem *)ep + i, 0); | ||
257 | |||
258 | /* point to bds */ | ||
259 | W16(ep, sen_genscc.scc_rbase, fep->ring_mem_addr); | ||
260 | W16(ep, sen_genscc.scc_tbase, | ||
261 | fep->ring_mem_addr + sizeof(cbd_t) * fpi->rx_ring); | ||
262 | |||
263 | /* Initialize function code registers for big-endian. | ||
264 | */ | ||
265 | #ifndef CONFIG_NOT_COHERENT_CACHE | ||
266 | W8(ep, sen_genscc.scc_rfcr, SCC_EB | SCC_GBL); | ||
267 | W8(ep, sen_genscc.scc_tfcr, SCC_EB | SCC_GBL); | ||
268 | #else | ||
269 | W8(ep, sen_genscc.scc_rfcr, SCC_EB); | ||
270 | W8(ep, sen_genscc.scc_tfcr, SCC_EB); | ||
271 | #endif | ||
272 | |||
273 | /* Set maximum bytes per receive buffer. | ||
274 | * This appears to be an Ethernet frame size, not the buffer | ||
275 | * fragment size. It must be a multiple of four. | ||
276 | */ | ||
277 | W16(ep, sen_genscc.scc_mrblr, 0x5f0); | ||
278 | |||
279 | /* Set CRC preset and mask. | ||
280 | */ | ||
281 | W32(ep, sen_cpres, 0xffffffff); | ||
282 | W32(ep, sen_cmask, 0xdebb20e3); | ||
283 | |||
284 | W32(ep, sen_crcec, 0); /* CRC Error counter */ | ||
285 | W32(ep, sen_alec, 0); /* alignment error counter */ | ||
286 | W32(ep, sen_disfc, 0); /* discard frame counter */ | ||
287 | |||
288 | W16(ep, sen_pads, 0x8888); /* Tx short frame pad character */ | ||
289 | W16(ep, sen_retlim, 15); /* Retry limit threshold */ | ||
290 | |||
291 | W16(ep, sen_maxflr, 0x5ee); /* maximum frame length register */ | ||
292 | |||
293 | W16(ep, sen_minflr, PKT_MINBUF_SIZE); /* minimum frame length register */ | ||
294 | |||
295 | W16(ep, sen_maxd1, 0x000005f0); /* maximum DMA1 length */ | ||
296 | W16(ep, sen_maxd2, 0x000005f0); /* maximum DMA2 length */ | ||
297 | |||
298 | /* Clear hash tables. | ||
299 | */ | ||
300 | W16(ep, sen_gaddr1, 0); | ||
301 | W16(ep, sen_gaddr2, 0); | ||
302 | W16(ep, sen_gaddr3, 0); | ||
303 | W16(ep, sen_gaddr4, 0); | ||
304 | W16(ep, sen_iaddr1, 0); | ||
305 | W16(ep, sen_iaddr2, 0); | ||
306 | W16(ep, sen_iaddr3, 0); | ||
307 | W16(ep, sen_iaddr4, 0); | ||
308 | |||
309 | /* set address | ||
310 | */ | ||
311 | mac = dev->dev_addr; | ||
312 | paddrh = ((u16) mac[5] << 8) | mac[4]; | ||
313 | paddrm = ((u16) mac[3] << 8) | mac[2]; | ||
314 | paddrl = ((u16) mac[1] << 8) | mac[0]; | ||
315 | |||
316 | W16(ep, sen_paddrh, paddrh); | ||
317 | W16(ep, sen_paddrm, paddrm); | ||
318 | W16(ep, sen_paddrl, paddrl); | ||
319 | |||
320 | W16(ep, sen_pper, 0); | ||
321 | W16(ep, sen_taddrl, 0); | ||
322 | W16(ep, sen_taddrm, 0); | ||
323 | W16(ep, sen_taddrh, 0); | ||
324 | |||
325 | fs_init_bds(dev); | ||
326 | |||
327 | scc_cr_cmd(fep, CPM_CR_INIT_TRX); | ||
328 | |||
329 | W16(sccp, scc_scce, 0xffff); | ||
330 | |||
331 | /* Enable interrupts we wish to service. | ||
332 | */ | ||
333 | W16(sccp, scc_sccm, SCCE_ENET_TXE | SCCE_ENET_RXF | SCCE_ENET_TXB); | ||
334 | |||
335 | /* Set GSMR_H to enable all normal operating modes. | ||
336 | * Set GSMR_L to enable Ethernet to MC68160. | ||
337 | */ | ||
338 | W32(sccp, scc_gsmrh, 0); | ||
339 | W32(sccp, scc_gsmrl, | ||
340 | SCC_GSMRL_TCI | SCC_GSMRL_TPL_48 | SCC_GSMRL_TPP_10 | | ||
341 | SCC_GSMRL_MODE_ENET); | ||
342 | |||
343 | /* Set sync/delimiters. | ||
344 | */ | ||
345 | W16(sccp, scc_dsr, 0xd555); | ||
346 | |||
347 | /* Set processing mode. Use Ethernet CRC, catch broadcast, and | ||
348 | * start frame search 22 bit times after RENA. | ||
349 | */ | ||
350 | W16(sccp, scc_psmr, SCC_PSMR_ENCRC | SCC_PSMR_NIB22); | ||
351 | |||
352 | /* Set full duplex mode if needed */ | ||
353 | if (fep->phydev->duplex) | ||
354 | S16(sccp, scc_psmr, SCC_PSMR_LPB | SCC_PSMR_FDE); | ||
355 | |||
356 | S32(sccp, scc_gsmrl, SCC_GSMRL_ENR | SCC_GSMRL_ENT); | ||
357 | } | ||
358 | |||
359 | static void stop(struct net_device *dev) | ||
360 | { | ||
361 | struct fs_enet_private *fep = netdev_priv(dev); | ||
362 | scc_t __iomem *sccp = fep->scc.sccp; | ||
363 | int i; | ||
364 | |||
365 | for (i = 0; (R16(sccp, scc_sccm) == 0) && i < SCC_RESET_DELAY; i++) | ||
366 | udelay(1); | ||
367 | |||
368 | if (i == SCC_RESET_DELAY) | ||
369 | dev_warn(fep->dev, "SCC timeout on graceful transmit stop\n"); | ||
370 | |||
371 | W16(sccp, scc_sccm, 0); | ||
372 | C32(sccp, scc_gsmrl, SCC_GSMRL_ENR | SCC_GSMRL_ENT); | ||
373 | |||
374 | fs_cleanup_bds(dev); | ||
375 | } | ||
376 | |||
377 | static void napi_clear_rx_event(struct net_device *dev) | ||
378 | { | ||
379 | struct fs_enet_private *fep = netdev_priv(dev); | ||
380 | scc_t __iomem *sccp = fep->scc.sccp; | ||
381 | |||
382 | W16(sccp, scc_scce, SCC_NAPI_RX_EVENT_MSK); | ||
383 | } | ||
384 | |||
385 | static void napi_enable_rx(struct net_device *dev) | ||
386 | { | ||
387 | struct fs_enet_private *fep = netdev_priv(dev); | ||
388 | scc_t __iomem *sccp = fep->scc.sccp; | ||
389 | |||
390 | S16(sccp, scc_sccm, SCC_NAPI_RX_EVENT_MSK); | ||
391 | } | ||
392 | |||
393 | static void napi_disable_rx(struct net_device *dev) | ||
394 | { | ||
395 | struct fs_enet_private *fep = netdev_priv(dev); | ||
396 | scc_t __iomem *sccp = fep->scc.sccp; | ||
397 | |||
398 | C16(sccp, scc_sccm, SCC_NAPI_RX_EVENT_MSK); | ||
399 | } | ||
400 | |||
401 | static void rx_bd_done(struct net_device *dev) | ||
402 | { | ||
403 | /* nothing */ | ||
404 | } | ||
405 | |||
406 | static void tx_kickstart(struct net_device *dev) | ||
407 | { | ||
408 | /* nothing */ | ||
409 | } | ||
410 | |||
411 | static u32 get_int_events(struct net_device *dev) | ||
412 | { | ||
413 | struct fs_enet_private *fep = netdev_priv(dev); | ||
414 | scc_t __iomem *sccp = fep->scc.sccp; | ||
415 | |||
416 | return (u32) R16(sccp, scc_scce); | ||
417 | } | ||
418 | |||
419 | static void clear_int_events(struct net_device *dev, u32 int_events) | ||
420 | { | ||
421 | struct fs_enet_private *fep = netdev_priv(dev); | ||
422 | scc_t __iomem *sccp = fep->scc.sccp; | ||
423 | |||
424 | W16(sccp, scc_scce, int_events & 0xffff); | ||
425 | } | ||
426 | |||
427 | static void ev_error(struct net_device *dev, u32 int_events) | ||
428 | { | ||
429 | struct fs_enet_private *fep = netdev_priv(dev); | ||
430 | |||
431 | dev_warn(fep->dev, "SCC ERROR(s) 0x%x\n", int_events); | ||
432 | } | ||
433 | |||
434 | static int get_regs(struct net_device *dev, void *p, int *sizep) | ||
435 | { | ||
436 | struct fs_enet_private *fep = netdev_priv(dev); | ||
437 | |||
438 | if (*sizep < sizeof(scc_t) + sizeof(scc_enet_t __iomem *)) | ||
439 | return -EINVAL; | ||
440 | |||
441 | memcpy_fromio(p, fep->scc.sccp, sizeof(scc_t)); | ||
442 | p = (char *)p + sizeof(scc_t); | ||
443 | |||
444 | memcpy_fromio(p, fep->scc.ep, sizeof(scc_enet_t __iomem *)); | ||
445 | |||
446 | return 0; | ||
447 | } | ||
448 | |||
449 | static int get_regs_len(struct net_device *dev) | ||
450 | { | ||
451 | return sizeof(scc_t) + sizeof(scc_enet_t __iomem *); | ||
452 | } | ||
453 | |||
454 | static void tx_restart(struct net_device *dev) | ||
455 | { | ||
456 | struct fs_enet_private *fep = netdev_priv(dev); | ||
457 | |||
458 | scc_cr_cmd(fep, CPM_CR_RESTART_TX); | ||
459 | } | ||
460 | |||
461 | |||
462 | |||
463 | /*************************************************************************/ | ||
464 | |||
465 | const struct fs_ops fs_scc_ops = { | ||
466 | .setup_data = setup_data, | ||
467 | .cleanup_data = cleanup_data, | ||
468 | .set_multicast_list = set_multicast_list, | ||
469 | .restart = restart, | ||
470 | .stop = stop, | ||
471 | .napi_clear_rx_event = napi_clear_rx_event, | ||
472 | .napi_enable_rx = napi_enable_rx, | ||
473 | .napi_disable_rx = napi_disable_rx, | ||
474 | .rx_bd_done = rx_bd_done, | ||
475 | .tx_kickstart = tx_kickstart, | ||
476 | .get_int_events = get_int_events, | ||
477 | .clear_int_events = clear_int_events, | ||
478 | .ev_error = ev_error, | ||
479 | .get_regs = get_regs, | ||
480 | .get_regs_len = get_regs_len, | ||
481 | .tx_restart = tx_restart, | ||
482 | .allocate_bd = allocate_bd, | ||
483 | .free_bd = free_bd, | ||
484 | }; | ||
diff --git a/drivers/net/fs_enet/mii-bitbang.c b/drivers/net/fs_enet/mii-bitbang.c new file mode 100644 index 00000000000..b09270b5d0a --- /dev/null +++ b/drivers/net/fs_enet/mii-bitbang.c | |||
@@ -0,0 +1,246 @@ | |||
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 | #include <linux/module.h> | ||
16 | #include <linux/ioport.h> | ||
17 | #include <linux/slab.h> | ||
18 | #include <linux/init.h> | ||
19 | #include <linux/interrupt.h> | ||
20 | #include <linux/netdevice.h> | ||
21 | #include <linux/etherdevice.h> | ||
22 | #include <linux/mii.h> | ||
23 | #include <linux/platform_device.h> | ||
24 | #include <linux/mdio-bitbang.h> | ||
25 | #include <linux/of_mdio.h> | ||
26 | #include <linux/of_platform.h> | ||
27 | |||
28 | #include "fs_enet.h" | ||
29 | |||
30 | struct bb_info { | ||
31 | struct mdiobb_ctrl ctrl; | ||
32 | __be32 __iomem *dir; | ||
33 | __be32 __iomem *dat; | ||
34 | u32 mdio_msk; | ||
35 | u32 mdc_msk; | ||
36 | }; | ||
37 | |||
38 | /* FIXME: If any other users of GPIO crop up, then these will have to | ||
39 | * have some sort of global synchronization to avoid races with other | ||
40 | * pins on the same port. The ideal solution would probably be to | ||
41 | * bind the ports to a GPIO driver, and have this be a client of it. | ||
42 | */ | ||
43 | static inline void bb_set(u32 __iomem *p, u32 m) | ||
44 | { | ||
45 | out_be32(p, in_be32(p) | m); | ||
46 | } | ||
47 | |||
48 | static inline void bb_clr(u32 __iomem *p, u32 m) | ||
49 | { | ||
50 | out_be32(p, in_be32(p) & ~m); | ||
51 | } | ||
52 | |||
53 | static inline int bb_read(u32 __iomem *p, u32 m) | ||
54 | { | ||
55 | return (in_be32(p) & m) != 0; | ||
56 | } | ||
57 | |||
58 | static inline void mdio_dir(struct mdiobb_ctrl *ctrl, int dir) | ||
59 | { | ||
60 | struct bb_info *bitbang = container_of(ctrl, struct bb_info, ctrl); | ||
61 | |||
62 | if (dir) | ||
63 | bb_set(bitbang->dir, bitbang->mdio_msk); | ||
64 | else | ||
65 | bb_clr(bitbang->dir, bitbang->mdio_msk); | ||
66 | |||
67 | /* Read back to flush the write. */ | ||
68 | in_be32(bitbang->dir); | ||
69 | } | ||
70 | |||
71 | static inline int mdio_read(struct mdiobb_ctrl *ctrl) | ||
72 | { | ||
73 | struct bb_info *bitbang = container_of(ctrl, struct bb_info, ctrl); | ||
74 | return bb_read(bitbang->dat, bitbang->mdio_msk); | ||
75 | } | ||
76 | |||
77 | static inline void mdio(struct mdiobb_ctrl *ctrl, int what) | ||
78 | { | ||
79 | struct bb_info *bitbang = container_of(ctrl, struct bb_info, ctrl); | ||
80 | |||
81 | if (what) | ||
82 | bb_set(bitbang->dat, bitbang->mdio_msk); | ||
83 | else | ||
84 | bb_clr(bitbang->dat, bitbang->mdio_msk); | ||
85 | |||
86 | /* Read back to flush the write. */ | ||
87 | in_be32(bitbang->dat); | ||
88 | } | ||
89 | |||
90 | static inline void mdc(struct mdiobb_ctrl *ctrl, int what) | ||
91 | { | ||
92 | struct bb_info *bitbang = container_of(ctrl, struct bb_info, ctrl); | ||
93 | |||
94 | if (what) | ||
95 | bb_set(bitbang->dat, bitbang->mdc_msk); | ||
96 | else | ||
97 | bb_clr(bitbang->dat, bitbang->mdc_msk); | ||
98 | |||
99 | /* Read back to flush the write. */ | ||
100 | in_be32(bitbang->dat); | ||
101 | } | ||
102 | |||
103 | static struct mdiobb_ops bb_ops = { | ||
104 | .owner = THIS_MODULE, | ||
105 | .set_mdc = mdc, | ||
106 | .set_mdio_dir = mdio_dir, | ||
107 | .set_mdio_data = mdio, | ||
108 | .get_mdio_data = mdio_read, | ||
109 | }; | ||
110 | |||
111 | static int __devinit fs_mii_bitbang_init(struct mii_bus *bus, | ||
112 | struct device_node *np) | ||
113 | { | ||
114 | struct resource res; | ||
115 | const u32 *data; | ||
116 | int mdio_pin, mdc_pin, len; | ||
117 | struct bb_info *bitbang = bus->priv; | ||
118 | |||
119 | int ret = of_address_to_resource(np, 0, &res); | ||
120 | if (ret) | ||
121 | return ret; | ||
122 | |||
123 | if (resource_size(&res) <= 13) | ||
124 | return -ENODEV; | ||
125 | |||
126 | /* This should really encode the pin number as well, but all | ||
127 | * we get is an int, and the odds of multiple bitbang mdio buses | ||
128 | * is low enough that it's not worth going too crazy. | ||
129 | */ | ||
130 | snprintf(bus->id, MII_BUS_ID_SIZE, "%x", res.start); | ||
131 | |||
132 | data = of_get_property(np, "fsl,mdio-pin", &len); | ||
133 | if (!data || len != 4) | ||
134 | return -ENODEV; | ||
135 | mdio_pin = *data; | ||
136 | |||
137 | data = of_get_property(np, "fsl,mdc-pin", &len); | ||
138 | if (!data || len != 4) | ||
139 | return -ENODEV; | ||
140 | mdc_pin = *data; | ||
141 | |||
142 | bitbang->dir = ioremap(res.start, resource_size(&res)); | ||
143 | if (!bitbang->dir) | ||
144 | return -ENOMEM; | ||
145 | |||
146 | bitbang->dat = bitbang->dir + 4; | ||
147 | bitbang->mdio_msk = 1 << (31 - mdio_pin); | ||
148 | bitbang->mdc_msk = 1 << (31 - mdc_pin); | ||
149 | |||
150 | return 0; | ||
151 | } | ||
152 | |||
153 | static int __devinit fs_enet_mdio_probe(struct platform_device *ofdev) | ||
154 | { | ||
155 | struct mii_bus *new_bus; | ||
156 | struct bb_info *bitbang; | ||
157 | int ret = -ENOMEM; | ||
158 | |||
159 | bitbang = kzalloc(sizeof(struct bb_info), GFP_KERNEL); | ||
160 | if (!bitbang) | ||
161 | goto out; | ||
162 | |||
163 | bitbang->ctrl.ops = &bb_ops; | ||
164 | |||
165 | new_bus = alloc_mdio_bitbang(&bitbang->ctrl); | ||
166 | if (!new_bus) | ||
167 | goto out_free_priv; | ||
168 | |||
169 | new_bus->name = "CPM2 Bitbanged MII", | ||
170 | |||
171 | ret = fs_mii_bitbang_init(new_bus, ofdev->dev.of_node); | ||
172 | if (ret) | ||
173 | goto out_free_bus; | ||
174 | |||
175 | new_bus->phy_mask = ~0; | ||
176 | new_bus->irq = kmalloc(sizeof(int) * PHY_MAX_ADDR, GFP_KERNEL); | ||
177 | if (!new_bus->irq) | ||
178 | goto out_unmap_regs; | ||
179 | |||
180 | new_bus->parent = &ofdev->dev; | ||
181 | dev_set_drvdata(&ofdev->dev, new_bus); | ||
182 | |||
183 | ret = of_mdiobus_register(new_bus, ofdev->dev.of_node); | ||
184 | if (ret) | ||
185 | goto out_free_irqs; | ||
186 | |||
187 | return 0; | ||
188 | |||
189 | out_free_irqs: | ||
190 | dev_set_drvdata(&ofdev->dev, NULL); | ||
191 | kfree(new_bus->irq); | ||
192 | out_unmap_regs: | ||
193 | iounmap(bitbang->dir); | ||
194 | out_free_bus: | ||
195 | free_mdio_bitbang(new_bus); | ||
196 | out_free_priv: | ||
197 | kfree(bitbang); | ||
198 | out: | ||
199 | return ret; | ||
200 | } | ||
201 | |||
202 | static int fs_enet_mdio_remove(struct platform_device *ofdev) | ||
203 | { | ||
204 | struct mii_bus *bus = dev_get_drvdata(&ofdev->dev); | ||
205 | struct bb_info *bitbang = bus->priv; | ||
206 | |||
207 | mdiobus_unregister(bus); | ||
208 | dev_set_drvdata(&ofdev->dev, NULL); | ||
209 | kfree(bus->irq); | ||
210 | free_mdio_bitbang(bus); | ||
211 | iounmap(bitbang->dir); | ||
212 | kfree(bitbang); | ||
213 | |||
214 | return 0; | ||
215 | } | ||
216 | |||
217 | static struct of_device_id fs_enet_mdio_bb_match[] = { | ||
218 | { | ||
219 | .compatible = "fsl,cpm2-mdio-bitbang", | ||
220 | }, | ||
221 | {}, | ||
222 | }; | ||
223 | MODULE_DEVICE_TABLE(of, fs_enet_mdio_bb_match); | ||
224 | |||
225 | static struct platform_driver fs_enet_bb_mdio_driver = { | ||
226 | .driver = { | ||
227 | .name = "fsl-bb-mdio", | ||
228 | .owner = THIS_MODULE, | ||
229 | .of_match_table = fs_enet_mdio_bb_match, | ||
230 | }, | ||
231 | .probe = fs_enet_mdio_probe, | ||
232 | .remove = fs_enet_mdio_remove, | ||
233 | }; | ||
234 | |||
235 | static int fs_enet_mdio_bb_init(void) | ||
236 | { | ||
237 | return platform_driver_register(&fs_enet_bb_mdio_driver); | ||
238 | } | ||
239 | |||
240 | static void fs_enet_mdio_bb_exit(void) | ||
241 | { | ||
242 | platform_driver_unregister(&fs_enet_bb_mdio_driver); | ||
243 | } | ||
244 | |||
245 | module_init(fs_enet_mdio_bb_init); | ||
246 | module_exit(fs_enet_mdio_bb_exit); | ||
diff --git a/drivers/net/fs_enet/mii-fec.c b/drivers/net/fs_enet/mii-fec.c new file mode 100644 index 00000000000..e0e9d6c35d8 --- /dev/null +++ b/drivers/net/fs_enet/mii-fec.c | |||
@@ -0,0 +1,251 @@ | |||
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 | #include <linux/module.h> | ||
16 | #include <linux/types.h> | ||
17 | #include <linux/kernel.h> | ||
18 | #include <linux/string.h> | ||
19 | #include <linux/ptrace.h> | ||
20 | #include <linux/errno.h> | ||
21 | #include <linux/ioport.h> | ||
22 | #include <linux/slab.h> | ||
23 | #include <linux/interrupt.h> | ||
24 | #include <linux/init.h> | ||
25 | #include <linux/delay.h> | ||
26 | #include <linux/netdevice.h> | ||
27 | #include <linux/etherdevice.h> | ||
28 | #include <linux/skbuff.h> | ||
29 | #include <linux/spinlock.h> | ||
30 | #include <linux/mii.h> | ||
31 | #include <linux/ethtool.h> | ||
32 | #include <linux/bitops.h> | ||
33 | #include <linux/platform_device.h> | ||
34 | #include <linux/of_platform.h> | ||
35 | |||
36 | #include <asm/pgtable.h> | ||
37 | #include <asm/irq.h> | ||
38 | #include <asm/uaccess.h> | ||
39 | #include <asm/mpc5xxx.h> | ||
40 | |||
41 | #include "fs_enet.h" | ||
42 | #include "fec.h" | ||
43 | |||
44 | /* Make MII read/write commands for the FEC. | ||
45 | */ | ||
46 | #define mk_mii_read(REG) (0x60020000 | ((REG & 0x1f) << 18)) | ||
47 | #define mk_mii_write(REG, VAL) (0x50020000 | ((REG & 0x1f) << 18) | (VAL & 0xffff)) | ||
48 | #define mk_mii_end 0 | ||
49 | |||
50 | #define FEC_MII_LOOPS 10000 | ||
51 | |||
52 | static int fs_enet_fec_mii_read(struct mii_bus *bus , int phy_id, int location) | ||
53 | { | ||
54 | struct fec_info* fec = bus->priv; | ||
55 | struct fec __iomem *fecp = fec->fecp; | ||
56 | int i, ret = -1; | ||
57 | |||
58 | BUG_ON((in_be32(&fecp->fec_r_cntrl) & FEC_RCNTRL_MII_MODE) == 0); | ||
59 | |||
60 | /* Add PHY address to register command. */ | ||
61 | out_be32(&fecp->fec_mii_data, (phy_id << 23) | mk_mii_read(location)); | ||
62 | |||
63 | for (i = 0; i < FEC_MII_LOOPS; i++) | ||
64 | if ((in_be32(&fecp->fec_ievent) & FEC_ENET_MII) != 0) | ||
65 | break; | ||
66 | |||
67 | if (i < FEC_MII_LOOPS) { | ||
68 | out_be32(&fecp->fec_ievent, FEC_ENET_MII); | ||
69 | ret = in_be32(&fecp->fec_mii_data) & 0xffff; | ||
70 | } | ||
71 | |||
72 | return ret; | ||
73 | } | ||
74 | |||
75 | static int fs_enet_fec_mii_write(struct mii_bus *bus, int phy_id, int location, u16 val) | ||
76 | { | ||
77 | struct fec_info* fec = bus->priv; | ||
78 | struct fec __iomem *fecp = fec->fecp; | ||
79 | int i; | ||
80 | |||
81 | /* this must never happen */ | ||
82 | BUG_ON((in_be32(&fecp->fec_r_cntrl) & FEC_RCNTRL_MII_MODE) == 0); | ||
83 | |||
84 | /* Add PHY address to register command. */ | ||
85 | out_be32(&fecp->fec_mii_data, (phy_id << 23) | mk_mii_write(location, val)); | ||
86 | |||
87 | for (i = 0; i < FEC_MII_LOOPS; i++) | ||
88 | if ((in_be32(&fecp->fec_ievent) & FEC_ENET_MII) != 0) | ||
89 | break; | ||
90 | |||
91 | if (i < FEC_MII_LOOPS) | ||
92 | out_be32(&fecp->fec_ievent, FEC_ENET_MII); | ||
93 | |||
94 | return 0; | ||
95 | |||
96 | } | ||
97 | |||
98 | static int fs_enet_fec_mii_reset(struct mii_bus *bus) | ||
99 | { | ||
100 | /* nothing here - for now */ | ||
101 | return 0; | ||
102 | } | ||
103 | |||
104 | static struct of_device_id fs_enet_mdio_fec_match[]; | ||
105 | static int __devinit fs_enet_mdio_probe(struct platform_device *ofdev) | ||
106 | { | ||
107 | const struct of_device_id *match; | ||
108 | struct resource res; | ||
109 | struct mii_bus *new_bus; | ||
110 | struct fec_info *fec; | ||
111 | int (*get_bus_freq)(struct device_node *); | ||
112 | int ret = -ENOMEM, clock, speed; | ||
113 | |||
114 | match = of_match_device(fs_enet_mdio_fec_match, &ofdev->dev); | ||
115 | if (!match) | ||
116 | return -EINVAL; | ||
117 | get_bus_freq = match->data; | ||
118 | |||
119 | new_bus = mdiobus_alloc(); | ||
120 | if (!new_bus) | ||
121 | goto out; | ||
122 | |||
123 | fec = kzalloc(sizeof(struct fec_info), GFP_KERNEL); | ||
124 | if (!fec) | ||
125 | goto out_mii; | ||
126 | |||
127 | new_bus->priv = fec; | ||
128 | new_bus->name = "FEC MII Bus"; | ||
129 | new_bus->read = &fs_enet_fec_mii_read; | ||
130 | new_bus->write = &fs_enet_fec_mii_write; | ||
131 | new_bus->reset = &fs_enet_fec_mii_reset; | ||
132 | |||
133 | ret = of_address_to_resource(ofdev->dev.of_node, 0, &res); | ||
134 | if (ret) | ||
135 | goto out_res; | ||
136 | |||
137 | snprintf(new_bus->id, MII_BUS_ID_SIZE, "%x", res.start); | ||
138 | |||
139 | fec->fecp = ioremap(res.start, resource_size(&res)); | ||
140 | if (!fec->fecp) | ||
141 | goto out_fec; | ||
142 | |||
143 | if (get_bus_freq) { | ||
144 | clock = get_bus_freq(ofdev->dev.of_node); | ||
145 | if (!clock) { | ||
146 | /* Use maximum divider if clock is unknown */ | ||
147 | dev_warn(&ofdev->dev, "could not determine IPS clock\n"); | ||
148 | clock = 0x3F * 5000000; | ||
149 | } | ||
150 | } else | ||
151 | clock = ppc_proc_freq; | ||
152 | |||
153 | /* | ||
154 | * Scale for a MII clock <= 2.5 MHz | ||
155 | * Note that only 6 bits (25:30) are available for MII speed. | ||
156 | */ | ||
157 | speed = (clock + 4999999) / 5000000; | ||
158 | if (speed > 0x3F) { | ||
159 | speed = 0x3F; | ||
160 | dev_err(&ofdev->dev, | ||
161 | "MII clock (%d Hz) exceeds max (2.5 MHz)\n", | ||
162 | clock / speed); | ||
163 | } | ||
164 | |||
165 | fec->mii_speed = speed << 1; | ||
166 | |||
167 | setbits32(&fec->fecp->fec_r_cntrl, FEC_RCNTRL_MII_MODE); | ||
168 | setbits32(&fec->fecp->fec_ecntrl, FEC_ECNTRL_PINMUX | | ||
169 | FEC_ECNTRL_ETHER_EN); | ||
170 | out_be32(&fec->fecp->fec_ievent, FEC_ENET_MII); | ||
171 | clrsetbits_be32(&fec->fecp->fec_mii_speed, 0x7E, fec->mii_speed); | ||
172 | |||
173 | new_bus->phy_mask = ~0; | ||
174 | new_bus->irq = kmalloc(sizeof(int) * PHY_MAX_ADDR, GFP_KERNEL); | ||
175 | if (!new_bus->irq) | ||
176 | goto out_unmap_regs; | ||
177 | |||
178 | new_bus->parent = &ofdev->dev; | ||
179 | dev_set_drvdata(&ofdev->dev, new_bus); | ||
180 | |||
181 | ret = of_mdiobus_register(new_bus, ofdev->dev.of_node); | ||
182 | if (ret) | ||
183 | goto out_free_irqs; | ||
184 | |||
185 | return 0; | ||
186 | |||
187 | out_free_irqs: | ||
188 | dev_set_drvdata(&ofdev->dev, NULL); | ||
189 | kfree(new_bus->irq); | ||
190 | out_unmap_regs: | ||
191 | iounmap(fec->fecp); | ||
192 | out_res: | ||
193 | out_fec: | ||
194 | kfree(fec); | ||
195 | out_mii: | ||
196 | mdiobus_free(new_bus); | ||
197 | out: | ||
198 | return ret; | ||
199 | } | ||
200 | |||
201 | static int fs_enet_mdio_remove(struct platform_device *ofdev) | ||
202 | { | ||
203 | struct mii_bus *bus = dev_get_drvdata(&ofdev->dev); | ||
204 | struct fec_info *fec = bus->priv; | ||
205 | |||
206 | mdiobus_unregister(bus); | ||
207 | dev_set_drvdata(&ofdev->dev, NULL); | ||
208 | kfree(bus->irq); | ||
209 | iounmap(fec->fecp); | ||
210 | kfree(fec); | ||
211 | mdiobus_free(bus); | ||
212 | |||
213 | return 0; | ||
214 | } | ||
215 | |||
216 | static struct of_device_id fs_enet_mdio_fec_match[] = { | ||
217 | { | ||
218 | .compatible = "fsl,pq1-fec-mdio", | ||
219 | }, | ||
220 | #if defined(CONFIG_PPC_MPC512x) | ||
221 | { | ||
222 | .compatible = "fsl,mpc5121-fec-mdio", | ||
223 | .data = mpc5xxx_get_bus_frequency, | ||
224 | }, | ||
225 | #endif | ||
226 | {}, | ||
227 | }; | ||
228 | MODULE_DEVICE_TABLE(of, fs_enet_mdio_fec_match); | ||
229 | |||
230 | static struct platform_driver fs_enet_fec_mdio_driver = { | ||
231 | .driver = { | ||
232 | .name = "fsl-fec-mdio", | ||
233 | .owner = THIS_MODULE, | ||
234 | .of_match_table = fs_enet_mdio_fec_match, | ||
235 | }, | ||
236 | .probe = fs_enet_mdio_probe, | ||
237 | .remove = fs_enet_mdio_remove, | ||
238 | }; | ||
239 | |||
240 | static int fs_enet_mdio_fec_init(void) | ||
241 | { | ||
242 | return platform_driver_register(&fs_enet_fec_mdio_driver); | ||
243 | } | ||
244 | |||
245 | static void fs_enet_mdio_fec_exit(void) | ||
246 | { | ||
247 | platform_driver_unregister(&fs_enet_fec_mdio_driver); | ||
248 | } | ||
249 | |||
250 | module_init(fs_enet_mdio_fec_init); | ||
251 | module_exit(fs_enet_mdio_fec_exit); | ||