diff options
author | Pantelis Antoniou <pantelis.antoniou@gmail.com> | 2005-10-28 16:25:58 -0400 |
---|---|---|
committer | Jeff Garzik <jgarzik@pobox.com> | 2005-10-28 16:25:58 -0400 |
commit | 48257c4f168e5d040394aeca4d37b59f68e0d36b (patch) | |
tree | 7e553a6018862338d80fb5b0e4070a371a8fb001 /drivers/net/fs_enet/mac-scc.c | |
parent | d8840ac907c7943bc7e196b11812adfa95cb28ef (diff) |
Add fs_enet ethernet network driver, for several embedded platforms.
Diffstat (limited to 'drivers/net/fs_enet/mac-scc.c')
-rw-r--r-- | drivers/net/fs_enet/mac-scc.c | 524 |
1 files changed, 524 insertions, 0 deletions
diff --git a/drivers/net/fs_enet/mac-scc.c b/drivers/net/fs_enet/mac-scc.c new file mode 100644 index 000000000000..d8c6e9cadcf5 --- /dev/null +++ b/drivers/net/fs_enet/mac-scc.c | |||
@@ -0,0 +1,524 @@ | |||
1 | /* | ||
2 | * Ethernet on Serial Communications Controller (SCC) driver for Motorola MPC8xx and MPC82xx. | ||
3 | * | ||
4 | * Copyright (c) 2003 Intracom S.A. | ||
5 | * by Pantelis Antoniou <panto@intracom.gr> | ||
6 | * | ||
7 | * 2005 (c) MontaVista Software, Inc. | ||
8 | * Vitaly Bordug <vbordug@ru.mvista.com> | ||
9 | * | ||
10 | * This file is licensed under the terms of the GNU General Public License | ||
11 | * version 2. This program is licensed "as is" without any warranty of any | ||
12 | * kind, whether express or implied. | ||
13 | */ | ||
14 | |||
15 | #include <linux/config.h> | ||
16 | #include <linux/module.h> | ||
17 | #include <linux/kernel.h> | ||
18 | #include <linux/types.h> | ||
19 | #include <linux/sched.h> | ||
20 | #include <linux/string.h> | ||
21 | #include <linux/ptrace.h> | ||
22 | #include <linux/errno.h> | ||
23 | #include <linux/ioport.h> | ||
24 | #include <linux/slab.h> | ||
25 | #include <linux/interrupt.h> | ||
26 | #include <linux/pci.h> | ||
27 | #include <linux/init.h> | ||
28 | #include <linux/delay.h> | ||
29 | #include <linux/netdevice.h> | ||
30 | #include <linux/etherdevice.h> | ||
31 | #include <linux/skbuff.h> | ||
32 | #include <linux/spinlock.h> | ||
33 | #include <linux/mii.h> | ||
34 | #include <linux/ethtool.h> | ||
35 | #include <linux/bitops.h> | ||
36 | #include <linux/fs.h> | ||
37 | |||
38 | #include <asm/irq.h> | ||
39 | #include <asm/uaccess.h> | ||
40 | |||
41 | #ifdef CONFIG_8xx | ||
42 | #include <asm/8xx_immap.h> | ||
43 | #include <asm/pgtable.h> | ||
44 | #include <asm/mpc8xx.h> | ||
45 | #include <asm/commproc.h> | ||
46 | #endif | ||
47 | |||
48 | #include "fs_enet.h" | ||
49 | |||
50 | /*************************************************/ | ||
51 | |||
52 | #if defined(CONFIG_CPM1) | ||
53 | /* for a 8xx __raw_xxx's are sufficient */ | ||
54 | #define __fs_out32(addr, x) __raw_writel(x, addr) | ||
55 | #define __fs_out16(addr, x) __raw_writew(x, addr) | ||
56 | #define __fs_out8(addr, x) __raw_writeb(x, addr) | ||
57 | #define __fs_in32(addr) __raw_readl(addr) | ||
58 | #define __fs_in16(addr) __raw_readw(addr) | ||
59 | #define __fs_in8(addr) __raw_readb(addr) | ||
60 | #else | ||
61 | /* for others play it safe */ | ||
62 | #define __fs_out32(addr, x) out_be32(addr, x) | ||
63 | #define __fs_out16(addr, x) out_be16(addr, x) | ||
64 | #define __fs_in32(addr) in_be32(addr) | ||
65 | #define __fs_in16(addr) in_be16(addr) | ||
66 | #endif | ||
67 | |||
68 | /* write, read, set bits, clear bits */ | ||
69 | #define W32(_p, _m, _v) __fs_out32(&(_p)->_m, (_v)) | ||
70 | #define R32(_p, _m) __fs_in32(&(_p)->_m) | ||
71 | #define S32(_p, _m, _v) W32(_p, _m, R32(_p, _m) | (_v)) | ||
72 | #define C32(_p, _m, _v) W32(_p, _m, R32(_p, _m) & ~(_v)) | ||
73 | |||
74 | #define W16(_p, _m, _v) __fs_out16(&(_p)->_m, (_v)) | ||
75 | #define R16(_p, _m) __fs_in16(&(_p)->_m) | ||
76 | #define S16(_p, _m, _v) W16(_p, _m, R16(_p, _m) | (_v)) | ||
77 | #define C16(_p, _m, _v) W16(_p, _m, R16(_p, _m) & ~(_v)) | ||
78 | |||
79 | #define W8(_p, _m, _v) __fs_out8(&(_p)->_m, (_v)) | ||
80 | #define R8(_p, _m) __fs_in8(&(_p)->_m) | ||
81 | #define S8(_p, _m, _v) W8(_p, _m, R8(_p, _m) | (_v)) | ||
82 | #define C8(_p, _m, _v) W8(_p, _m, R8(_p, _m) & ~(_v)) | ||
83 | |||
84 | #define SCC_MAX_MULTICAST_ADDRS 64 | ||
85 | |||
86 | /* | ||
87 | * Delay to wait for SCC reset command to complete (in us) | ||
88 | */ | ||
89 | #define SCC_RESET_DELAY 50 | ||
90 | #define MAX_CR_CMD_LOOPS 10000 | ||
91 | |||
92 | static inline int scc_cr_cmd(struct fs_enet_private *fep, u32 op) | ||
93 | { | ||
94 | cpm8xx_t *cpmp = &((immap_t *)fs_enet_immap)->im_cpm; | ||
95 | u32 v, ch; | ||
96 | int i = 0; | ||
97 | |||
98 | ch = fep->scc.idx << 2; | ||
99 | v = mk_cr_cmd(ch, op); | ||
100 | W16(cpmp, cp_cpcr, v | CPM_CR_FLG); | ||
101 | for (i = 0; i < MAX_CR_CMD_LOOPS; i++) | ||
102 | if ((R16(cpmp, cp_cpcr) & CPM_CR_FLG) == 0) | ||
103 | break; | ||
104 | |||
105 | if (i >= MAX_CR_CMD_LOOPS) { | ||
106 | printk(KERN_ERR "%s(): Not able to issue CPM command\n", | ||
107 | __FUNCTION__); | ||
108 | return 1; | ||
109 | } | ||
110 | return 0; | ||
111 | } | ||
112 | |||
113 | static int do_pd_setup(struct fs_enet_private *fep) | ||
114 | { | ||
115 | struct platform_device *pdev = to_platform_device(fep->dev); | ||
116 | struct resource *r; | ||
117 | |||
118 | /* Fill out IRQ field */ | ||
119 | fep->interrupt = platform_get_irq_byname(pdev, "interrupt"); | ||
120 | |||
121 | r = platform_get_resource_byname(pdev, IORESOURCE_MEM, "regs"); | ||
122 | fep->scc.sccp = (void *)r->start; | ||
123 | |||
124 | if (fep->scc.sccp == NULL) | ||
125 | return -EINVAL; | ||
126 | |||
127 | r = platform_get_resource_byname(pdev, IORESOURCE_MEM, "pram"); | ||
128 | fep->scc.ep = (void *)r->start; | ||
129 | |||
130 | if (fep->scc.ep == NULL) | ||
131 | return -EINVAL; | ||
132 | |||
133 | return 0; | ||
134 | } | ||
135 | |||
136 | #define SCC_NAPI_RX_EVENT_MSK (SCCE_ENET_RXF | SCCE_ENET_RXB) | ||
137 | #define SCC_RX_EVENT (SCCE_ENET_RXF) | ||
138 | #define SCC_TX_EVENT (SCCE_ENET_TXB) | ||
139 | #define SCC_ERR_EVENT_MSK (SCCE_ENET_TXE | SCCE_ENET_BSY) | ||
140 | |||
141 | static int setup_data(struct net_device *dev) | ||
142 | { | ||
143 | struct fs_enet_private *fep = netdev_priv(dev); | ||
144 | const struct fs_platform_info *fpi = fep->fpi; | ||
145 | |||
146 | fep->scc.idx = fs_get_scc_index(fpi->fs_no); | ||
147 | if ((unsigned int)fep->fcc.idx > 4) /* max 4 SCCs */ | ||
148 | return -EINVAL; | ||
149 | |||
150 | do_pd_setup(fep); | ||
151 | |||
152 | fep->scc.hthi = 0; | ||
153 | fep->scc.htlo = 0; | ||
154 | |||
155 | fep->ev_napi_rx = SCC_NAPI_RX_EVENT_MSK; | ||
156 | fep->ev_rx = SCC_RX_EVENT; | ||
157 | fep->ev_tx = SCC_TX_EVENT; | ||
158 | fep->ev_err = SCC_ERR_EVENT_MSK; | ||
159 | |||
160 | return 0; | ||
161 | } | ||
162 | |||
163 | static int allocate_bd(struct net_device *dev) | ||
164 | { | ||
165 | struct fs_enet_private *fep = netdev_priv(dev); | ||
166 | const struct fs_platform_info *fpi = fep->fpi; | ||
167 | |||
168 | fep->ring_mem_addr = cpm_dpalloc((fpi->tx_ring + fpi->rx_ring) * | ||
169 | sizeof(cbd_t), 8); | ||
170 | if (IS_DPERR(fep->ring_mem_addr)) | ||
171 | return -ENOMEM; | ||
172 | |||
173 | fep->ring_base = cpm_dpram_addr(fep->ring_mem_addr); | ||
174 | |||
175 | return 0; | ||
176 | } | ||
177 | |||
178 | static void free_bd(struct net_device *dev) | ||
179 | { | ||
180 | struct fs_enet_private *fep = netdev_priv(dev); | ||
181 | |||
182 | if (fep->ring_base) | ||
183 | cpm_dpfree(fep->ring_mem_addr); | ||
184 | } | ||
185 | |||
186 | static void cleanup_data(struct net_device *dev) | ||
187 | { | ||
188 | /* nothing */ | ||
189 | } | ||
190 | |||
191 | static void set_promiscuous_mode(struct net_device *dev) | ||
192 | { | ||
193 | struct fs_enet_private *fep = netdev_priv(dev); | ||
194 | scc_t *sccp = fep->scc.sccp; | ||
195 | |||
196 | S16(sccp, scc_psmr, SCC_PSMR_PRO); | ||
197 | } | ||
198 | |||
199 | static void set_multicast_start(struct net_device *dev) | ||
200 | { | ||
201 | struct fs_enet_private *fep = netdev_priv(dev); | ||
202 | scc_enet_t *ep = fep->scc.ep; | ||
203 | |||
204 | W16(ep, sen_gaddr1, 0); | ||
205 | W16(ep, sen_gaddr2, 0); | ||
206 | W16(ep, sen_gaddr3, 0); | ||
207 | W16(ep, sen_gaddr4, 0); | ||
208 | } | ||
209 | |||
210 | static void set_multicast_one(struct net_device *dev, const u8 * mac) | ||
211 | { | ||
212 | struct fs_enet_private *fep = netdev_priv(dev); | ||
213 | scc_enet_t *ep = fep->scc.ep; | ||
214 | u16 taddrh, taddrm, taddrl; | ||
215 | |||
216 | taddrh = ((u16) mac[5] << 8) | mac[4]; | ||
217 | taddrm = ((u16) mac[3] << 8) | mac[2]; | ||
218 | taddrl = ((u16) mac[1] << 8) | mac[0]; | ||
219 | |||
220 | W16(ep, sen_taddrh, taddrh); | ||
221 | W16(ep, sen_taddrm, taddrm); | ||
222 | W16(ep, sen_taddrl, taddrl); | ||
223 | scc_cr_cmd(fep, CPM_CR_SET_GADDR); | ||
224 | } | ||
225 | |||
226 | static void set_multicast_finish(struct net_device *dev) | ||
227 | { | ||
228 | struct fs_enet_private *fep = netdev_priv(dev); | ||
229 | scc_t *sccp = fep->scc.sccp; | ||
230 | scc_enet_t *ep = fep->scc.ep; | ||
231 | |||
232 | /* clear promiscuous always */ | ||
233 | C16(sccp, scc_psmr, SCC_PSMR_PRO); | ||
234 | |||
235 | /* if all multi or too many multicasts; just enable all */ | ||
236 | if ((dev->flags & IFF_ALLMULTI) != 0 || | ||
237 | dev->mc_count > SCC_MAX_MULTICAST_ADDRS) { | ||
238 | |||
239 | W16(ep, sen_gaddr1, 0xffff); | ||
240 | W16(ep, sen_gaddr2, 0xffff); | ||
241 | W16(ep, sen_gaddr3, 0xffff); | ||
242 | W16(ep, sen_gaddr4, 0xffff); | ||
243 | } | ||
244 | } | ||
245 | |||
246 | static void set_multicast_list(struct net_device *dev) | ||
247 | { | ||
248 | struct dev_mc_list *pmc; | ||
249 | |||
250 | if ((dev->flags & IFF_PROMISC) == 0) { | ||
251 | set_multicast_start(dev); | ||
252 | for (pmc = dev->mc_list; pmc != NULL; pmc = pmc->next) | ||
253 | set_multicast_one(dev, pmc->dmi_addr); | ||
254 | set_multicast_finish(dev); | ||
255 | } else | ||
256 | set_promiscuous_mode(dev); | ||
257 | } | ||
258 | |||
259 | /* | ||
260 | * This function is called to start or restart the FEC during a link | ||
261 | * change. This only happens when switching between half and full | ||
262 | * duplex. | ||
263 | */ | ||
264 | static void restart(struct net_device *dev) | ||
265 | { | ||
266 | struct fs_enet_private *fep = netdev_priv(dev); | ||
267 | scc_t *sccp = fep->scc.sccp; | ||
268 | scc_enet_t *ep = fep->scc.ep; | ||
269 | const struct fs_platform_info *fpi = fep->fpi; | ||
270 | u16 paddrh, paddrm, paddrl; | ||
271 | const unsigned char *mac; | ||
272 | int i; | ||
273 | |||
274 | C32(sccp, scc_gsmrl, SCC_GSMRL_ENR | SCC_GSMRL_ENT); | ||
275 | |||
276 | /* clear everything (slow & steady does it) */ | ||
277 | for (i = 0; i < sizeof(*ep); i++) | ||
278 | __fs_out8((char *)ep + i, 0); | ||
279 | |||
280 | /* point to bds */ | ||
281 | W16(ep, sen_genscc.scc_rbase, fep->ring_mem_addr); | ||
282 | W16(ep, sen_genscc.scc_tbase, | ||
283 | fep->ring_mem_addr + sizeof(cbd_t) * fpi->rx_ring); | ||
284 | |||
285 | /* Initialize function code registers for big-endian. | ||
286 | */ | ||
287 | W8(ep, sen_genscc.scc_rfcr, SCC_EB); | ||
288 | W8(ep, sen_genscc.scc_tfcr, SCC_EB); | ||
289 | |||
290 | /* Set maximum bytes per receive buffer. | ||
291 | * This appears to be an Ethernet frame size, not the buffer | ||
292 | * fragment size. It must be a multiple of four. | ||
293 | */ | ||
294 | W16(ep, sen_genscc.scc_mrblr, 0x5f0); | ||
295 | |||
296 | /* Set CRC preset and mask. | ||
297 | */ | ||
298 | W32(ep, sen_cpres, 0xffffffff); | ||
299 | W32(ep, sen_cmask, 0xdebb20e3); | ||
300 | |||
301 | W32(ep, sen_crcec, 0); /* CRC Error counter */ | ||
302 | W32(ep, sen_alec, 0); /* alignment error counter */ | ||
303 | W32(ep, sen_disfc, 0); /* discard frame counter */ | ||
304 | |||
305 | W16(ep, sen_pads, 0x8888); /* Tx short frame pad character */ | ||
306 | W16(ep, sen_retlim, 15); /* Retry limit threshold */ | ||
307 | |||
308 | W16(ep, sen_maxflr, 0x5ee); /* maximum frame length register */ | ||
309 | |||
310 | W16(ep, sen_minflr, PKT_MINBUF_SIZE); /* minimum frame length register */ | ||
311 | |||
312 | W16(ep, sen_maxd1, 0x000005f0); /* maximum DMA1 length */ | ||
313 | W16(ep, sen_maxd2, 0x000005f0); /* maximum DMA2 length */ | ||
314 | |||
315 | /* Clear hash tables. | ||
316 | */ | ||
317 | W16(ep, sen_gaddr1, 0); | ||
318 | W16(ep, sen_gaddr2, 0); | ||
319 | W16(ep, sen_gaddr3, 0); | ||
320 | W16(ep, sen_gaddr4, 0); | ||
321 | W16(ep, sen_iaddr1, 0); | ||
322 | W16(ep, sen_iaddr2, 0); | ||
323 | W16(ep, sen_iaddr3, 0); | ||
324 | W16(ep, sen_iaddr4, 0); | ||
325 | |||
326 | /* set address | ||
327 | */ | ||
328 | mac = dev->dev_addr; | ||
329 | paddrh = ((u16) mac[5] << 8) | mac[4]; | ||
330 | paddrm = ((u16) mac[3] << 8) | mac[2]; | ||
331 | paddrl = ((u16) mac[1] << 8) | mac[0]; | ||
332 | |||
333 | W16(ep, sen_paddrh, paddrh); | ||
334 | W16(ep, sen_paddrm, paddrm); | ||
335 | W16(ep, sen_paddrl, paddrl); | ||
336 | |||
337 | W16(ep, sen_pper, 0); | ||
338 | W16(ep, sen_taddrl, 0); | ||
339 | W16(ep, sen_taddrm, 0); | ||
340 | W16(ep, sen_taddrh, 0); | ||
341 | |||
342 | fs_init_bds(dev); | ||
343 | |||
344 | scc_cr_cmd(fep, CPM_CR_INIT_TRX); | ||
345 | |||
346 | W16(sccp, scc_scce, 0xffff); | ||
347 | |||
348 | /* Enable interrupts we wish to service. | ||
349 | */ | ||
350 | W16(sccp, scc_sccm, SCCE_ENET_TXE | SCCE_ENET_RXF | SCCE_ENET_TXB); | ||
351 | |||
352 | /* Set GSMR_H to enable all normal operating modes. | ||
353 | * Set GSMR_L to enable Ethernet to MC68160. | ||
354 | */ | ||
355 | W32(sccp, scc_gsmrh, 0); | ||
356 | W32(sccp, scc_gsmrl, | ||
357 | SCC_GSMRL_TCI | SCC_GSMRL_TPL_48 | SCC_GSMRL_TPP_10 | | ||
358 | SCC_GSMRL_MODE_ENET); | ||
359 | |||
360 | /* Set sync/delimiters. | ||
361 | */ | ||
362 | W16(sccp, scc_dsr, 0xd555); | ||
363 | |||
364 | /* Set processing mode. Use Ethernet CRC, catch broadcast, and | ||
365 | * start frame search 22 bit times after RENA. | ||
366 | */ | ||
367 | W16(sccp, scc_psmr, SCC_PSMR_ENCRC | SCC_PSMR_NIB22); | ||
368 | |||
369 | /* Set full duplex mode if needed */ | ||
370 | if (fep->duplex) | ||
371 | S16(sccp, scc_psmr, SCC_PSMR_LPB | SCC_PSMR_FDE); | ||
372 | |||
373 | S32(sccp, scc_gsmrl, SCC_GSMRL_ENR | SCC_GSMRL_ENT); | ||
374 | } | ||
375 | |||
376 | static void stop(struct net_device *dev) | ||
377 | { | ||
378 | struct fs_enet_private *fep = netdev_priv(dev); | ||
379 | scc_t *sccp = fep->scc.sccp; | ||
380 | int i; | ||
381 | |||
382 | for (i = 0; (R16(sccp, scc_sccm) == 0) && i < SCC_RESET_DELAY; i++) | ||
383 | udelay(1); | ||
384 | |||
385 | if (i == SCC_RESET_DELAY) | ||
386 | printk(KERN_WARNING DRV_MODULE_NAME | ||
387 | ": %s SCC timeout on graceful transmit stop\n", | ||
388 | dev->name); | ||
389 | |||
390 | W16(sccp, scc_sccm, 0); | ||
391 | C32(sccp, scc_gsmrl, SCC_GSMRL_ENR | SCC_GSMRL_ENT); | ||
392 | |||
393 | fs_cleanup_bds(dev); | ||
394 | } | ||
395 | |||
396 | static void pre_request_irq(struct net_device *dev, int irq) | ||
397 | { | ||
398 | immap_t *immap = fs_enet_immap; | ||
399 | u32 siel; | ||
400 | |||
401 | /* SIU interrupt */ | ||
402 | if (irq >= SIU_IRQ0 && irq < SIU_LEVEL7) { | ||
403 | |||
404 | siel = in_be32(&immap->im_siu_conf.sc_siel); | ||
405 | if ((irq & 1) == 0) | ||
406 | siel |= (0x80000000 >> irq); | ||
407 | else | ||
408 | siel &= ~(0x80000000 >> (irq & ~1)); | ||
409 | out_be32(&immap->im_siu_conf.sc_siel, siel); | ||
410 | } | ||
411 | } | ||
412 | |||
413 | static void post_free_irq(struct net_device *dev, int irq) | ||
414 | { | ||
415 | /* nothing */ | ||
416 | } | ||
417 | |||
418 | static void napi_clear_rx_event(struct net_device *dev) | ||
419 | { | ||
420 | struct fs_enet_private *fep = netdev_priv(dev); | ||
421 | scc_t *sccp = fep->scc.sccp; | ||
422 | |||
423 | W16(sccp, scc_scce, SCC_NAPI_RX_EVENT_MSK); | ||
424 | } | ||
425 | |||
426 | static void napi_enable_rx(struct net_device *dev) | ||
427 | { | ||
428 | struct fs_enet_private *fep = netdev_priv(dev); | ||
429 | scc_t *sccp = fep->scc.sccp; | ||
430 | |||
431 | S16(sccp, scc_sccm, SCC_NAPI_RX_EVENT_MSK); | ||
432 | } | ||
433 | |||
434 | static void napi_disable_rx(struct net_device *dev) | ||
435 | { | ||
436 | struct fs_enet_private *fep = netdev_priv(dev); | ||
437 | scc_t *sccp = fep->scc.sccp; | ||
438 | |||
439 | C16(sccp, scc_sccm, SCC_NAPI_RX_EVENT_MSK); | ||
440 | } | ||
441 | |||
442 | static void rx_bd_done(struct net_device *dev) | ||
443 | { | ||
444 | /* nothing */ | ||
445 | } | ||
446 | |||
447 | static void tx_kickstart(struct net_device *dev) | ||
448 | { | ||
449 | /* nothing */ | ||
450 | } | ||
451 | |||
452 | static u32 get_int_events(struct net_device *dev) | ||
453 | { | ||
454 | struct fs_enet_private *fep = netdev_priv(dev); | ||
455 | scc_t *sccp = fep->scc.sccp; | ||
456 | |||
457 | return (u32) R16(sccp, scc_scce); | ||
458 | } | ||
459 | |||
460 | static void clear_int_events(struct net_device *dev, u32 int_events) | ||
461 | { | ||
462 | struct fs_enet_private *fep = netdev_priv(dev); | ||
463 | scc_t *sccp = fep->scc.sccp; | ||
464 | |||
465 | W16(sccp, scc_scce, int_events & 0xffff); | ||
466 | } | ||
467 | |||
468 | static void ev_error(struct net_device *dev, u32 int_events) | ||
469 | { | ||
470 | printk(KERN_WARNING DRV_MODULE_NAME | ||
471 | ": %s SCC ERROR(s) 0x%x\n", dev->name, int_events); | ||
472 | } | ||
473 | |||
474 | static int get_regs(struct net_device *dev, void *p, int *sizep) | ||
475 | { | ||
476 | struct fs_enet_private *fep = netdev_priv(dev); | ||
477 | |||
478 | if (*sizep < sizeof(scc_t) + sizeof(scc_enet_t)) | ||
479 | return -EINVAL; | ||
480 | |||
481 | memcpy_fromio(p, fep->scc.sccp, sizeof(scc_t)); | ||
482 | p = (char *)p + sizeof(scc_t); | ||
483 | |||
484 | memcpy_fromio(p, fep->scc.ep, sizeof(scc_enet_t)); | ||
485 | |||
486 | return 0; | ||
487 | } | ||
488 | |||
489 | static int get_regs_len(struct net_device *dev) | ||
490 | { | ||
491 | return sizeof(scc_t) + sizeof(scc_enet_t); | ||
492 | } | ||
493 | |||
494 | static void tx_restart(struct net_device *dev) | ||
495 | { | ||
496 | struct fs_enet_private *fep = netdev_priv(dev); | ||
497 | |||
498 | scc_cr_cmd(fep, CPM_CR_RESTART_TX); | ||
499 | } | ||
500 | |||
501 | /*************************************************************************/ | ||
502 | |||
503 | const struct fs_ops fs_scc_ops = { | ||
504 | .setup_data = setup_data, | ||
505 | .cleanup_data = cleanup_data, | ||
506 | .set_multicast_list = set_multicast_list, | ||
507 | .restart = restart, | ||
508 | .stop = stop, | ||
509 | .pre_request_irq = pre_request_irq, | ||
510 | .post_free_irq = post_free_irq, | ||
511 | .napi_clear_rx_event = napi_clear_rx_event, | ||
512 | .napi_enable_rx = napi_enable_rx, | ||
513 | .napi_disable_rx = napi_disable_rx, | ||
514 | .rx_bd_done = rx_bd_done, | ||
515 | .tx_kickstart = tx_kickstart, | ||
516 | .get_int_events = get_int_events, | ||
517 | .clear_int_events = clear_int_events, | ||
518 | .ev_error = ev_error, | ||
519 | .get_regs = get_regs, | ||
520 | .get_regs_len = get_regs_len, | ||
521 | .tx_restart = tx_restart, | ||
522 | .allocate_bd = allocate_bd, | ||
523 | .free_bd = free_bd, | ||
524 | }; | ||