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-fcc.c | |
parent | d8840ac907c7943bc7e196b11812adfa95cb28ef (diff) |
Add fs_enet ethernet network driver, for several embedded platforms.
Diffstat (limited to 'drivers/net/fs_enet/mac-fcc.c')
-rw-r--r-- | drivers/net/fs_enet/mac-fcc.c | 578 |
1 files changed, 578 insertions, 0 deletions
diff --git a/drivers/net/fs_enet/mac-fcc.c b/drivers/net/fs_enet/mac-fcc.c new file mode 100644 index 000000000000..a940b96433c7 --- /dev/null +++ b/drivers/net/fs_enet/mac-fcc.c | |||
@@ -0,0 +1,578 @@ | |||
1 | /* | ||
2 | * FCC driver for Motorola MPC82xx (PQ2). | ||
3 | * | ||
4 | * Copyright (c) 2003 Intracom S.A. | ||
5 | * by Pantelis Antoniou <panto@intracom.gr> | ||
6 | * | ||
7 | * 2005 (c) MontaVista Software, Inc. | ||
8 | * Vitaly Bordug <vbordug@ru.mvista.com> | ||
9 | * | ||
10 | * This file is licensed under the terms of the GNU General Public License | ||
11 | * version 2. This program is licensed "as is" without any warranty of any | ||
12 | * kind, whether express or implied. | ||
13 | */ | ||
14 | |||
15 | #include <linux/config.h> | ||
16 | #include <linux/module.h> | ||
17 | #include <linux/kernel.h> | ||
18 | #include <linux/types.h> | ||
19 | #include <linux/sched.h> | ||
20 | #include <linux/string.h> | ||
21 | #include <linux/ptrace.h> | ||
22 | #include <linux/errno.h> | ||
23 | #include <linux/ioport.h> | ||
24 | #include <linux/slab.h> | ||
25 | #include <linux/interrupt.h> | ||
26 | #include <linux/pci.h> | ||
27 | #include <linux/init.h> | ||
28 | #include <linux/delay.h> | ||
29 | #include <linux/netdevice.h> | ||
30 | #include <linux/etherdevice.h> | ||
31 | #include <linux/skbuff.h> | ||
32 | #include <linux/spinlock.h> | ||
33 | #include <linux/mii.h> | ||
34 | #include <linux/ethtool.h> | ||
35 | #include <linux/bitops.h> | ||
36 | #include <linux/fs.h> | ||
37 | |||
38 | #include <asm/immap_cpm2.h> | ||
39 | #include <asm/mpc8260.h> | ||
40 | #include <asm/cpm2.h> | ||
41 | |||
42 | #include <asm/pgtable.h> | ||
43 | #include <asm/irq.h> | ||
44 | #include <asm/uaccess.h> | ||
45 | |||
46 | #include "fs_enet.h" | ||
47 | |||
48 | /*************************************************/ | ||
49 | |||
50 | /* FCC access macros */ | ||
51 | |||
52 | #define __fcc_out32(addr, x) out_be32((unsigned *)addr, x) | ||
53 | #define __fcc_out16(addr, x) out_be16((unsigned short *)addr, x) | ||
54 | #define __fcc_out8(addr, x) out_8((unsigned char *)addr, x) | ||
55 | #define __fcc_in32(addr) in_be32((unsigned *)addr) | ||
56 | #define __fcc_in16(addr) in_be16((unsigned short *)addr) | ||
57 | #define __fcc_in8(addr) in_8((unsigned char *)addr) | ||
58 | |||
59 | /* parameter space */ | ||
60 | |||
61 | /* write, read, set bits, clear bits */ | ||
62 | #define W32(_p, _m, _v) __fcc_out32(&(_p)->_m, (_v)) | ||
63 | #define R32(_p, _m) __fcc_in32(&(_p)->_m) | ||
64 | #define S32(_p, _m, _v) W32(_p, _m, R32(_p, _m) | (_v)) | ||
65 | #define C32(_p, _m, _v) W32(_p, _m, R32(_p, _m) & ~(_v)) | ||
66 | |||
67 | #define W16(_p, _m, _v) __fcc_out16(&(_p)->_m, (_v)) | ||
68 | #define R16(_p, _m) __fcc_in16(&(_p)->_m) | ||
69 | #define S16(_p, _m, _v) W16(_p, _m, R16(_p, _m) | (_v)) | ||
70 | #define C16(_p, _m, _v) W16(_p, _m, R16(_p, _m) & ~(_v)) | ||
71 | |||
72 | #define W8(_p, _m, _v) __fcc_out8(&(_p)->_m, (_v)) | ||
73 | #define R8(_p, _m) __fcc_in8(&(_p)->_m) | ||
74 | #define S8(_p, _m, _v) W8(_p, _m, R8(_p, _m) | (_v)) | ||
75 | #define C8(_p, _m, _v) W8(_p, _m, R8(_p, _m) & ~(_v)) | ||
76 | |||
77 | /*************************************************/ | ||
78 | |||
79 | #define FCC_MAX_MULTICAST_ADDRS 64 | ||
80 | |||
81 | #define mk_mii_read(REG) (0x60020000 | ((REG & 0x1f) << 18)) | ||
82 | #define mk_mii_write(REG, VAL) (0x50020000 | ((REG & 0x1f) << 18) | (VAL & 0xffff)) | ||
83 | #define mk_mii_end 0 | ||
84 | |||
85 | #define MAX_CR_CMD_LOOPS 10000 | ||
86 | |||
87 | static inline int fcc_cr_cmd(struct fs_enet_private *fep, u32 mcn, u32 op) | ||
88 | { | ||
89 | const struct fs_platform_info *fpi = fep->fpi; | ||
90 | |||
91 | cpm2_map_t *immap = fs_enet_immap; | ||
92 | cpm_cpm2_t *cpmp = &immap->im_cpm; | ||
93 | u32 v; | ||
94 | int i; | ||
95 | |||
96 | /* Currently I don't know what feature call will look like. But | ||
97 | I guess there'd be something like do_cpm_cmd() which will require page & sblock */ | ||
98 | v = mk_cr_cmd(fpi->cp_page, fpi->cp_block, mcn, op); | ||
99 | W32(cpmp, cp_cpcr, v | CPM_CR_FLG); | ||
100 | for (i = 0; i < MAX_CR_CMD_LOOPS; i++) | ||
101 | if ((R32(cpmp, cp_cpcr) & CPM_CR_FLG) == 0) | ||
102 | break; | ||
103 | |||
104 | if (i >= MAX_CR_CMD_LOOPS) { | ||
105 | printk(KERN_ERR "%s(): Not able to issue CPM command\n", | ||
106 | __FUNCTION__); | ||
107 | return 1; | ||
108 | } | ||
109 | |||
110 | return 0; | ||
111 | } | ||
112 | |||
113 | static int do_pd_setup(struct fs_enet_private *fep) | ||
114 | { | ||
115 | struct platform_device *pdev = to_platform_device(fep->dev); | ||
116 | struct resource *r; | ||
117 | |||
118 | /* Fill out IRQ field */ | ||
119 | fep->interrupt = platform_get_irq(pdev, 0); | ||
120 | |||
121 | /* Attach the memory for the FCC Parameter RAM */ | ||
122 | r = platform_get_resource_byname(pdev, IORESOURCE_MEM, "fcc_pram"); | ||
123 | fep->fcc.ep = (void *)r->start; | ||
124 | |||
125 | if (fep->fcc.ep == NULL) | ||
126 | return -EINVAL; | ||
127 | |||
128 | r = platform_get_resource_byname(pdev, IORESOURCE_MEM, "fcc_regs"); | ||
129 | fep->fcc.fccp = (void *)r->start; | ||
130 | |||
131 | if (fep->fcc.fccp == NULL) | ||
132 | return -EINVAL; | ||
133 | |||
134 | fep->fcc.fcccp = (void *)fep->fpi->fcc_regs_c; | ||
135 | |||
136 | if (fep->fcc.fcccp == NULL) | ||
137 | return -EINVAL; | ||
138 | |||
139 | return 0; | ||
140 | } | ||
141 | |||
142 | #define FCC_NAPI_RX_EVENT_MSK (FCC_ENET_RXF | FCC_ENET_RXB) | ||
143 | #define FCC_RX_EVENT (FCC_ENET_RXF) | ||
144 | #define FCC_TX_EVENT (FCC_ENET_TXB) | ||
145 | #define FCC_ERR_EVENT_MSK (FCC_ENET_TXE | FCC_ENET_BSY) | ||
146 | |||
147 | static int setup_data(struct net_device *dev) | ||
148 | { | ||
149 | struct fs_enet_private *fep = netdev_priv(dev); | ||
150 | const struct fs_platform_info *fpi = fep->fpi; | ||
151 | |||
152 | fep->fcc.idx = fs_get_fcc_index(fpi->fs_no); | ||
153 | if ((unsigned int)fep->fcc.idx >= 3) /* max 3 FCCs */ | ||
154 | return -EINVAL; | ||
155 | |||
156 | fep->fcc.mem = (void *)fpi->mem_offset; | ||
157 | |||
158 | if (do_pd_setup(fep) != 0) | ||
159 | return -EINVAL; | ||
160 | |||
161 | fep->ev_napi_rx = FCC_NAPI_RX_EVENT_MSK; | ||
162 | fep->ev_rx = FCC_RX_EVENT; | ||
163 | fep->ev_tx = FCC_TX_EVENT; | ||
164 | fep->ev_err = FCC_ERR_EVENT_MSK; | ||
165 | |||
166 | return 0; | ||
167 | } | ||
168 | |||
169 | static int allocate_bd(struct net_device *dev) | ||
170 | { | ||
171 | struct fs_enet_private *fep = netdev_priv(dev); | ||
172 | const struct fs_platform_info *fpi = fep->fpi; | ||
173 | |||
174 | fep->ring_base = dma_alloc_coherent(fep->dev, | ||
175 | (fpi->tx_ring + fpi->rx_ring) * | ||
176 | sizeof(cbd_t), &fep->ring_mem_addr, | ||
177 | GFP_KERNEL); | ||
178 | if (fep->ring_base == NULL) | ||
179 | return -ENOMEM; | ||
180 | |||
181 | return 0; | ||
182 | } | ||
183 | |||
184 | static void free_bd(struct net_device *dev) | ||
185 | { | ||
186 | struct fs_enet_private *fep = netdev_priv(dev); | ||
187 | const struct fs_platform_info *fpi = fep->fpi; | ||
188 | |||
189 | if (fep->ring_base) | ||
190 | dma_free_coherent(fep->dev, | ||
191 | (fpi->tx_ring + fpi->rx_ring) * sizeof(cbd_t), | ||
192 | fep->ring_base, fep->ring_mem_addr); | ||
193 | } | ||
194 | |||
195 | static void cleanup_data(struct net_device *dev) | ||
196 | { | ||
197 | /* nothing */ | ||
198 | } | ||
199 | |||
200 | static void set_promiscuous_mode(struct net_device *dev) | ||
201 | { | ||
202 | struct fs_enet_private *fep = netdev_priv(dev); | ||
203 | fcc_t *fccp = fep->fcc.fccp; | ||
204 | |||
205 | S32(fccp, fcc_fpsmr, FCC_PSMR_PRO); | ||
206 | } | ||
207 | |||
208 | static void set_multicast_start(struct net_device *dev) | ||
209 | { | ||
210 | struct fs_enet_private *fep = netdev_priv(dev); | ||
211 | fcc_enet_t *ep = fep->fcc.ep; | ||
212 | |||
213 | W32(ep, fen_gaddrh, 0); | ||
214 | W32(ep, fen_gaddrl, 0); | ||
215 | } | ||
216 | |||
217 | static void set_multicast_one(struct net_device *dev, const u8 *mac) | ||
218 | { | ||
219 | struct fs_enet_private *fep = netdev_priv(dev); | ||
220 | fcc_enet_t *ep = fep->fcc.ep; | ||
221 | u16 taddrh, taddrm, taddrl; | ||
222 | |||
223 | taddrh = ((u16)mac[5] << 8) | mac[4]; | ||
224 | taddrm = ((u16)mac[3] << 8) | mac[2]; | ||
225 | taddrl = ((u16)mac[1] << 8) | mac[0]; | ||
226 | |||
227 | W16(ep, fen_taddrh, taddrh); | ||
228 | W16(ep, fen_taddrm, taddrm); | ||
229 | W16(ep, fen_taddrl, taddrl); | ||
230 | fcc_cr_cmd(fep, 0x0C, CPM_CR_SET_GADDR); | ||
231 | } | ||
232 | |||
233 | static void set_multicast_finish(struct net_device *dev) | ||
234 | { | ||
235 | struct fs_enet_private *fep = netdev_priv(dev); | ||
236 | fcc_t *fccp = fep->fcc.fccp; | ||
237 | fcc_enet_t *ep = fep->fcc.ep; | ||
238 | |||
239 | /* clear promiscuous always */ | ||
240 | C32(fccp, fcc_fpsmr, FCC_PSMR_PRO); | ||
241 | |||
242 | /* if all multi or too many multicasts; just enable all */ | ||
243 | if ((dev->flags & IFF_ALLMULTI) != 0 || | ||
244 | dev->mc_count > FCC_MAX_MULTICAST_ADDRS) { | ||
245 | |||
246 | W32(ep, fen_gaddrh, 0xffffffff); | ||
247 | W32(ep, fen_gaddrl, 0xffffffff); | ||
248 | } | ||
249 | |||
250 | /* read back */ | ||
251 | fep->fcc.gaddrh = R32(ep, fen_gaddrh); | ||
252 | fep->fcc.gaddrl = R32(ep, fen_gaddrl); | ||
253 | } | ||
254 | |||
255 | static void set_multicast_list(struct net_device *dev) | ||
256 | { | ||
257 | struct dev_mc_list *pmc; | ||
258 | |||
259 | if ((dev->flags & IFF_PROMISC) == 0) { | ||
260 | set_multicast_start(dev); | ||
261 | for (pmc = dev->mc_list; pmc != NULL; pmc = pmc->next) | ||
262 | set_multicast_one(dev, pmc->dmi_addr); | ||
263 | set_multicast_finish(dev); | ||
264 | } else | ||
265 | set_promiscuous_mode(dev); | ||
266 | } | ||
267 | |||
268 | static void restart(struct net_device *dev) | ||
269 | { | ||
270 | struct fs_enet_private *fep = netdev_priv(dev); | ||
271 | const struct fs_platform_info *fpi = fep->fpi; | ||
272 | fcc_t *fccp = fep->fcc.fccp; | ||
273 | fcc_c_t *fcccp = fep->fcc.fcccp; | ||
274 | fcc_enet_t *ep = fep->fcc.ep; | ||
275 | dma_addr_t rx_bd_base_phys, tx_bd_base_phys; | ||
276 | u16 paddrh, paddrm, paddrl; | ||
277 | u16 mem_addr; | ||
278 | const unsigned char *mac; | ||
279 | int i; | ||
280 | |||
281 | C32(fccp, fcc_gfmr, FCC_GFMR_ENR | FCC_GFMR_ENT); | ||
282 | |||
283 | /* clear everything (slow & steady does it) */ | ||
284 | for (i = 0; i < sizeof(*ep); i++) | ||
285 | __fcc_out8((char *)ep + i, 0); | ||
286 | |||
287 | /* get physical address */ | ||
288 | rx_bd_base_phys = fep->ring_mem_addr; | ||
289 | tx_bd_base_phys = rx_bd_base_phys + sizeof(cbd_t) * fpi->rx_ring; | ||
290 | |||
291 | /* point to bds */ | ||
292 | W32(ep, fen_genfcc.fcc_rbase, rx_bd_base_phys); | ||
293 | W32(ep, fen_genfcc.fcc_tbase, tx_bd_base_phys); | ||
294 | |||
295 | /* Set maximum bytes per receive buffer. | ||
296 | * It must be a multiple of 32. | ||
297 | */ | ||
298 | W16(ep, fen_genfcc.fcc_mrblr, PKT_MAXBLR_SIZE); | ||
299 | |||
300 | W32(ep, fen_genfcc.fcc_rstate, (CPMFCR_GBL | CPMFCR_EB) << 24); | ||
301 | W32(ep, fen_genfcc.fcc_tstate, (CPMFCR_GBL | CPMFCR_EB) << 24); | ||
302 | |||
303 | /* Allocate space in the reserved FCC area of DPRAM for the | ||
304 | * internal buffers. No one uses this space (yet), so we | ||
305 | * can do this. Later, we will add resource management for | ||
306 | * this area. | ||
307 | */ | ||
308 | |||
309 | mem_addr = (u32) fep->fcc.mem; /* de-fixup dpram offset */ | ||
310 | |||
311 | W16(ep, fen_genfcc.fcc_riptr, (mem_addr & 0xffff)); | ||
312 | W16(ep, fen_genfcc.fcc_tiptr, ((mem_addr + 32) & 0xffff)); | ||
313 | W16(ep, fen_padptr, mem_addr + 64); | ||
314 | |||
315 | /* fill with special symbol... */ | ||
316 | memset(fep->fcc.mem + fpi->dpram_offset + 64, 0x88, 32); | ||
317 | |||
318 | W32(ep, fen_genfcc.fcc_rbptr, 0); | ||
319 | W32(ep, fen_genfcc.fcc_tbptr, 0); | ||
320 | W32(ep, fen_genfcc.fcc_rcrc, 0); | ||
321 | W32(ep, fen_genfcc.fcc_tcrc, 0); | ||
322 | W16(ep, fen_genfcc.fcc_res1, 0); | ||
323 | W32(ep, fen_genfcc.fcc_res2, 0); | ||
324 | |||
325 | /* no CAM */ | ||
326 | W32(ep, fen_camptr, 0); | ||
327 | |||
328 | /* Set CRC preset and mask */ | ||
329 | W32(ep, fen_cmask, 0xdebb20e3); | ||
330 | W32(ep, fen_cpres, 0xffffffff); | ||
331 | |||
332 | W32(ep, fen_crcec, 0); /* CRC Error counter */ | ||
333 | W32(ep, fen_alec, 0); /* alignment error counter */ | ||
334 | W32(ep, fen_disfc, 0); /* discard frame counter */ | ||
335 | W16(ep, fen_retlim, 15); /* Retry limit threshold */ | ||
336 | W16(ep, fen_pper, 0); /* Normal persistence */ | ||
337 | |||
338 | /* set group address */ | ||
339 | W32(ep, fen_gaddrh, fep->fcc.gaddrh); | ||
340 | W32(ep, fen_gaddrl, fep->fcc.gaddrh); | ||
341 | |||
342 | /* Clear hash filter tables */ | ||
343 | W32(ep, fen_iaddrh, 0); | ||
344 | W32(ep, fen_iaddrl, 0); | ||
345 | |||
346 | /* Clear the Out-of-sequence TxBD */ | ||
347 | W16(ep, fen_tfcstat, 0); | ||
348 | W16(ep, fen_tfclen, 0); | ||
349 | W32(ep, fen_tfcptr, 0); | ||
350 | |||
351 | W16(ep, fen_mflr, PKT_MAXBUF_SIZE); /* maximum frame length register */ | ||
352 | W16(ep, fen_minflr, PKT_MINBUF_SIZE); /* minimum frame length register */ | ||
353 | |||
354 | /* set address */ | ||
355 | mac = dev->dev_addr; | ||
356 | paddrh = ((u16)mac[5] << 8) | mac[4]; | ||
357 | paddrm = ((u16)mac[3] << 8) | mac[2]; | ||
358 | paddrl = ((u16)mac[1] << 8) | mac[0]; | ||
359 | |||
360 | W16(ep, fen_paddrh, paddrh); | ||
361 | W16(ep, fen_paddrm, paddrm); | ||
362 | W16(ep, fen_paddrl, paddrl); | ||
363 | |||
364 | W16(ep, fen_taddrh, 0); | ||
365 | W16(ep, fen_taddrm, 0); | ||
366 | W16(ep, fen_taddrl, 0); | ||
367 | |||
368 | W16(ep, fen_maxd1, 1520); /* maximum DMA1 length */ | ||
369 | W16(ep, fen_maxd2, 1520); /* maximum DMA2 length */ | ||
370 | |||
371 | /* Clear stat counters, in case we ever enable RMON */ | ||
372 | W32(ep, fen_octc, 0); | ||
373 | W32(ep, fen_colc, 0); | ||
374 | W32(ep, fen_broc, 0); | ||
375 | W32(ep, fen_mulc, 0); | ||
376 | W32(ep, fen_uspc, 0); | ||
377 | W32(ep, fen_frgc, 0); | ||
378 | W32(ep, fen_ospc, 0); | ||
379 | W32(ep, fen_jbrc, 0); | ||
380 | W32(ep, fen_p64c, 0); | ||
381 | W32(ep, fen_p65c, 0); | ||
382 | W32(ep, fen_p128c, 0); | ||
383 | W32(ep, fen_p256c, 0); | ||
384 | W32(ep, fen_p512c, 0); | ||
385 | W32(ep, fen_p1024c, 0); | ||
386 | |||
387 | W16(ep, fen_rfthr, 0); /* Suggested by manual */ | ||
388 | W16(ep, fen_rfcnt, 0); | ||
389 | W16(ep, fen_cftype, 0); | ||
390 | |||
391 | fs_init_bds(dev); | ||
392 | |||
393 | /* adjust to speed (for RMII mode) */ | ||
394 | if (fpi->use_rmii) { | ||
395 | if (fep->speed == 100) | ||
396 | C8(fcccp, fcc_gfemr, 0x20); | ||
397 | else | ||
398 | S8(fcccp, fcc_gfemr, 0x20); | ||
399 | } | ||
400 | |||
401 | fcc_cr_cmd(fep, 0x0c, CPM_CR_INIT_TRX); | ||
402 | |||
403 | /* clear events */ | ||
404 | W16(fccp, fcc_fcce, 0xffff); | ||
405 | |||
406 | /* Enable interrupts we wish to service */ | ||
407 | W16(fccp, fcc_fccm, FCC_ENET_TXE | FCC_ENET_RXF | FCC_ENET_TXB); | ||
408 | |||
409 | /* Set GFMR to enable Ethernet operating mode */ | ||
410 | W32(fccp, fcc_gfmr, FCC_GFMR_TCI | FCC_GFMR_MODE_ENET); | ||
411 | |||
412 | /* set sync/delimiters */ | ||
413 | W16(fccp, fcc_fdsr, 0xd555); | ||
414 | |||
415 | W32(fccp, fcc_fpsmr, FCC_PSMR_ENCRC); | ||
416 | |||
417 | if (fpi->use_rmii) | ||
418 | S32(fccp, fcc_fpsmr, FCC_PSMR_RMII); | ||
419 | |||
420 | /* adjust to duplex mode */ | ||
421 | if (fep->duplex) | ||
422 | S32(fccp, fcc_fpsmr, FCC_PSMR_FDE | FCC_PSMR_LPB); | ||
423 | else | ||
424 | C32(fccp, fcc_fpsmr, FCC_PSMR_FDE | FCC_PSMR_LPB); | ||
425 | |||
426 | S32(fccp, fcc_gfmr, FCC_GFMR_ENR | FCC_GFMR_ENT); | ||
427 | } | ||
428 | |||
429 | static void stop(struct net_device *dev) | ||
430 | { | ||
431 | struct fs_enet_private *fep = netdev_priv(dev); | ||
432 | fcc_t *fccp = fep->fcc.fccp; | ||
433 | |||
434 | /* stop ethernet */ | ||
435 | C32(fccp, fcc_gfmr, FCC_GFMR_ENR | FCC_GFMR_ENT); | ||
436 | |||
437 | /* clear events */ | ||
438 | W16(fccp, fcc_fcce, 0xffff); | ||
439 | |||
440 | /* clear interrupt mask */ | ||
441 | W16(fccp, fcc_fccm, 0); | ||
442 | |||
443 | fs_cleanup_bds(dev); | ||
444 | } | ||
445 | |||
446 | static void pre_request_irq(struct net_device *dev, int irq) | ||
447 | { | ||
448 | /* nothing */ | ||
449 | } | ||
450 | |||
451 | static void post_free_irq(struct net_device *dev, int irq) | ||
452 | { | ||
453 | /* nothing */ | ||
454 | } | ||
455 | |||
456 | static void napi_clear_rx_event(struct net_device *dev) | ||
457 | { | ||
458 | struct fs_enet_private *fep = netdev_priv(dev); | ||
459 | fcc_t *fccp = fep->fcc.fccp; | ||
460 | |||
461 | W16(fccp, fcc_fcce, FCC_NAPI_RX_EVENT_MSK); | ||
462 | } | ||
463 | |||
464 | static void napi_enable_rx(struct net_device *dev) | ||
465 | { | ||
466 | struct fs_enet_private *fep = netdev_priv(dev); | ||
467 | fcc_t *fccp = fep->fcc.fccp; | ||
468 | |||
469 | S16(fccp, fcc_fccm, FCC_NAPI_RX_EVENT_MSK); | ||
470 | } | ||
471 | |||
472 | static void napi_disable_rx(struct net_device *dev) | ||
473 | { | ||
474 | struct fs_enet_private *fep = netdev_priv(dev); | ||
475 | fcc_t *fccp = fep->fcc.fccp; | ||
476 | |||
477 | C16(fccp, fcc_fccm, FCC_NAPI_RX_EVENT_MSK); | ||
478 | } | ||
479 | |||
480 | static void rx_bd_done(struct net_device *dev) | ||
481 | { | ||
482 | /* nothing */ | ||
483 | } | ||
484 | |||
485 | static void tx_kickstart(struct net_device *dev) | ||
486 | { | ||
487 | /* nothing */ | ||
488 | } | ||
489 | |||
490 | static u32 get_int_events(struct net_device *dev) | ||
491 | { | ||
492 | struct fs_enet_private *fep = netdev_priv(dev); | ||
493 | fcc_t *fccp = fep->fcc.fccp; | ||
494 | |||
495 | return (u32)R16(fccp, fcc_fcce); | ||
496 | } | ||
497 | |||
498 | static void clear_int_events(struct net_device *dev, u32 int_events) | ||
499 | { | ||
500 | struct fs_enet_private *fep = netdev_priv(dev); | ||
501 | fcc_t *fccp = fep->fcc.fccp; | ||
502 | |||
503 | W16(fccp, fcc_fcce, int_events & 0xffff); | ||
504 | } | ||
505 | |||
506 | static void ev_error(struct net_device *dev, u32 int_events) | ||
507 | { | ||
508 | printk(KERN_WARNING DRV_MODULE_NAME | ||
509 | ": %s FS_ENET ERROR(s) 0x%x\n", dev->name, int_events); | ||
510 | } | ||
511 | |||
512 | int get_regs(struct net_device *dev, void *p, int *sizep) | ||
513 | { | ||
514 | struct fs_enet_private *fep = netdev_priv(dev); | ||
515 | |||
516 | if (*sizep < sizeof(fcc_t) + sizeof(fcc_c_t) + sizeof(fcc_enet_t)) | ||
517 | return -EINVAL; | ||
518 | |||
519 | memcpy_fromio(p, fep->fcc.fccp, sizeof(fcc_t)); | ||
520 | p = (char *)p + sizeof(fcc_t); | ||
521 | |||
522 | memcpy_fromio(p, fep->fcc.fcccp, sizeof(fcc_c_t)); | ||
523 | p = (char *)p + sizeof(fcc_c_t); | ||
524 | |||
525 | memcpy_fromio(p, fep->fcc.ep, sizeof(fcc_enet_t)); | ||
526 | |||
527 | return 0; | ||
528 | } | ||
529 | |||
530 | int get_regs_len(struct net_device *dev) | ||
531 | { | ||
532 | return sizeof(fcc_t) + sizeof(fcc_c_t) + sizeof(fcc_enet_t); | ||
533 | } | ||
534 | |||
535 | /* Some transmit errors cause the transmitter to shut | ||
536 | * down. We now issue a restart transmit. Since the | ||
537 | * errors close the BD and update the pointers, the restart | ||
538 | * _should_ pick up without having to reset any of our | ||
539 | * pointers either. Also, To workaround 8260 device erratum | ||
540 | * CPM37, we must disable and then re-enable the transmitter | ||
541 | * following a Late Collision, Underrun, or Retry Limit error. | ||
542 | */ | ||
543 | void tx_restart(struct net_device *dev) | ||
544 | { | ||
545 | struct fs_enet_private *fep = netdev_priv(dev); | ||
546 | fcc_t *fccp = fep->fcc.fccp; | ||
547 | |||
548 | C32(fccp, fcc_gfmr, FCC_GFMR_ENT); | ||
549 | udelay(10); | ||
550 | S32(fccp, fcc_gfmr, FCC_GFMR_ENT); | ||
551 | |||
552 | fcc_cr_cmd(fep, 0x0C, CPM_CR_RESTART_TX); | ||
553 | } | ||
554 | |||
555 | /*************************************************************************/ | ||
556 | |||
557 | const struct fs_ops fs_fcc_ops = { | ||
558 | .setup_data = setup_data, | ||
559 | .cleanup_data = cleanup_data, | ||
560 | .set_multicast_list = set_multicast_list, | ||
561 | .restart = restart, | ||
562 | .stop = stop, | ||
563 | .pre_request_irq = pre_request_irq, | ||
564 | .post_free_irq = post_free_irq, | ||
565 | .napi_clear_rx_event = napi_clear_rx_event, | ||
566 | .napi_enable_rx = napi_enable_rx, | ||
567 | .napi_disable_rx = napi_disable_rx, | ||
568 | .rx_bd_done = rx_bd_done, | ||
569 | .tx_kickstart = tx_kickstart, | ||
570 | .get_int_events = get_int_events, | ||
571 | .clear_int_events = clear_int_events, | ||
572 | .ev_error = ev_error, | ||
573 | .get_regs = get_regs, | ||
574 | .get_regs_len = get_regs_len, | ||
575 | .tx_restart = tx_restart, | ||
576 | .allocate_bd = allocate_bd, | ||
577 | .free_bd = free_bd, | ||
578 | }; | ||