MOXA linux-2.6.x / linux-2.6.9-uc0 from sdlinux-moxaart.tgz
[linux-2.6.9-moxart.git] / drivers / net / moxacpu_mac.c
Commit [+]AuthorDateLineData
28cc2cc5
JJ
Jonas Jensen2012-12-12 10:47:38 +01001
2/*
3 * This program is the Moxa CPU ethernet device driver.
4 *
5 * History:
6 * Date Author Comment
7 * 06-15-2005 Victor Yu. Create it. Make it for Faraday demo board.
8 * 11-04-2005 Victor Yu. Modify it to support Moxa CPU demo board.
9 */
10
11#include <linux/config.h>
12#include <linux/module.h>
13#include <linux/kernel.h>
14#include <linux/types.h>
15#include <linux/fcntl.h>
16#include <linux/interrupt.h>
17#include <linux/ioport.h>
18#include <linux/in.h>
19#include <linux/slab.h>
20#include <linux/string.h>
21#include <linux/errno.h>
22#include <linux/init.h>
23#include <linux/netdevice.h>
24#include <linux/etherdevice.h>
25#include <linux/spinlock.h>
26#include <linux/skbuff.h>
27#include <linux/device.h>
28#include <linux/dma-mapping.h>
29#include <linux/delay.h>
30#include <linux/workqueue.h>
31#include <asm/uaccess.h>
32#include <asm/system.h>
33#include <asm/bitops.h>
34#include <asm/io.h>
35#include <asm/irq.h>
36#include <asm/dma.h>
37#include "moxacpu_mac.h"
38
39//#define MCPU_MAC_DEBUG
40//#define USE_SCHEDULE_WORK
41
42#if (defined CONFIG_ARCH_IA241_32128)||(defined CONFIG_ARCH_IA241_16128)// add by Victor Yu. 05-22-2007
43#define CONFIG_ARCH_IA241
44#endif
45
46#if (defined CONFIG_ARCH_UC_7112_LX_PLUS_LITON)
47#define CONFIG_ARCH_UC_7112_LX_PLUS
48#endif
49
50#ifdef MCPU_MAC_DEBUG
51#define dbg_printk(x...) printk(x)
52#else // MCPU_MAC_DEBUG
53#define dbg_printk(x...)
54#endif // MCPU_MAC_DEBUG
55
56#define TX_DESC_NUM 64
57#define TX_DESC_NUM_MASK (TX_DESC_NUM-1)
58#define RX_DESC_NUM 64
59#define RX_DESC_NUM_MASK (RX_DESC_NUM-1)
60#define TX_BUF_SIZE 1600
61#define RX_BUF_SIZE 1600
62#if TX_BUF_SIZE >= TXBUF_SIZE_MAX
63#error Moxa CPU ethernet device driver Tx buffer size too large !
64#endif
65#if RX_BUF_SIZE >= RXBUF_SIZE_MAX
66#error Moxa CPU ethernet device driver Rx buffer size too large !
67#endif
68
69static mcpu_mac_priv_t mcpu_mac_priv;
70#ifdef CONFIG_ARCH_MOXACPU
71
72#if ( defined CONFIG_ARCH_IA240 ) || ( defined CONFIG_ARCH_IA241 ) || ( defined CONFIG_ARCH_UC_7112_LX_PLUS )
73static mcpu_mac_priv_t mcpu_mac_priv2;
74#endif
75
76#endif // CONFIG_ARCH_MOXACPU
77
78
79#ifdef HAVE_MULTICAST
80static int crc32( char * s, int length )
81{
82 /* indices */
83 int perByte;
84 int perBit;
85 /* crc polynomial for Ethernet */
86 const unsigned long poly=0xedb88320;
87 /* crc value - preinitialized to all 1's */
88 unsigned long crc_value=0xffffffff;
89
90 for ( perByte = 0; perByte < length; perByte ++ ) {
91 unsigned char c;
92
93 c = *(s++);
94 for ( perBit = 0; perBit < 8; perBit++ ) {
95 crc_value = (crc_value>>1)^
96 (((crc_value^c)&0x01)?poly:0);
97 c >>= 1;
98 }
99 }
100 return crc_value;
101}
102
103static void mcpu_mac_setmulticast(unsigned int ioaddr, int count, struct dev_mc_list * addrs )
104{
105 struct dev_mc_list *cur_addr;
106 int crc_val;
107
108 for (cur_addr = addrs ; cur_addr!=NULL ; cur_addr = cur_addr->next ) {
109 if ( !( *cur_addr->dmi_addr & 1 ) )
110 continue;
111 crc_val = crc32( cur_addr->dmi_addr, 6 );
112 crc_val = (crc_val>>26)&0x3f; // ยจรบ MSB 6 bit
113 if (crc_val >= 32)
114 outl(inl(ioaddr+MATH1_REG_OFFSET) | (1UL<<(crc_val-32)), ioaddr+MATH1_REG_OFFSET);
115 else
116 outl(inl(ioaddr+MATH0_REG_OFFSET) | (1UL<<crc_val), ioaddr+MATH0_REG_OFFSET);
117 }
118}
119
120static void mcpu_mac_set_multicast_list(struct net_device *dev)
121{
122 mcpu_mac_priv_t *priv=(mcpu_mac_priv_t *)dev->priv;
123 unsigned long flags;
124
125 save_flags(flags);
126 cli();
127#ifdef USE_SCHEDULE_WORK
128 spin_lock(&priv->rxlock);
129#endif
130 spin_lock(&priv->txlock);
131
132 if ( dev->flags & IFF_PROMISC )
133 priv->maccr |= RCV_ALL;
134 else
135 priv->maccr &= ~RCV_ALL;
136
137 if ( dev->flags & IFF_ALLMULTI )
138 priv->maccr |= RX_MULTIPKT;
139 else
140 priv->maccr &= ~RX_MULTIPKT;
141
142 if ( dev->mc_count ) {
143 priv->maccr |= RX_MULTIPKT; //add by Johnson.Liu 2007/07/06
144 priv->maccr |= HT_MULTI_EN;
145 mcpu_mac_setmulticast(dev->base_addr, dev->mc_count, dev->mc_list);
146 } else {
147 priv->maccr &= ~RX_MULTIPKT; //add by Johnson.Liu 2007/07/06
148 priv->maccr &= ~HT_MULTI_EN;
149 }
150
151 outl(priv->maccr, dev->base_addr+MACCR_REG_OFFSET);
152
153 spin_unlock(&priv->txlock);
154#ifdef USE_SCHEDULE_WORK
155 spin_unlock(&priv->rxlock);
156#endif
157 restore_flags(flags);
158}
159#endif // HAVE_MULTICAST
160
161#if 1 // add by Victor Yu. 07-04-2005
162static void mywordcopy(void *dest, void *source, int len)
163{
164 unsigned short *pd=(unsigned short *)dest;
165 unsigned short *ps=(unsigned short *)source;
166 int wlen=len>>1;
167
168 while ( wlen > 0 ) {
169 *pd++=*ps++;
170 wlen--;
171 }
172 if ( len & 1 )
173 *(unsigned char *)pd = *(unsigned char *)ps;
174}
175#endif // 07-04-2005
176
177static void mcpu_mac_recv(void *ptr)
178{
179 struct net_device *dev=(struct net_device *)ptr;
180 mcpu_mac_priv_t *priv=(mcpu_mac_priv_t *)dev->priv;
181 rx_desc_t *rxdesc;
182 int len;
183 struct sk_buff *skb;
184
185 unsigned char *data;
186#if 1 // add by Victor Yu. 07-04-2005
187 unsigned int ui;
188 int rxnow=priv->RxDescNow;
189#endif // 07-04-2005
190#ifndef USE_SCHEDULE_WORK
191 int loops=RX_DESC_NUM;
192#endif // USE_SCHEDULE_WORK
193
194 dbg_printk("mcpu_mac_recv test01\n");
195
196
197#if 0
198 dbg_printk("RxDescNow=%d, desc phy=0x%x, virt=0x%x, buf phy=0x%x, virt=0x%x\n", priv->RxDescNow, priv->phyRxDescBaseAddr+(priv->RxDescNow*sizeof(rx_desc_t)), (unsigned int)&priv->virtRxDescBaseAddr[priv->RxDescNow], priv->virtRxDescBaseAddr[priv->RxDescNow].rxdes2.phyRxBufBaseAddr, (unsigned int)priv->virtRxDescBaseAddr[priv->RxDescNow].rxdes2.virtRxBufBaseAddr);
199 dbg_printk("Now Rx desc des0=0x%x, des1=0x%x\n", priv->virtRxDescBaseAddr[priv->RxDescNow].rxdes0.ui, priv->virtRxDescBaseAddr[priv->RxDescNow].rxdes1.ui);
200#endif
201
202
203
204#ifdef USE_SCHEDULE_WORK
205 spin_lock(&priv->rxlock);
206#endif // USE_SCHEDULE_WORK
207repeat_recv:
208 rxdesc = &priv->virtRxDescBaseAddr[rxnow];
209#if 0 // mask by Victor Yu. 07-04-2005
210 if ( rxdesc->rxdes0.ubit.RxDMAOwn ) {
211#else // add by Victor Yu. 07-04-2005
212 ui = rxdesc->rxdes0.ui;
213 if ( ui & RXDMA_OWN ) {
214#endif // 07-04-2005
215#ifdef USE_SCHEDULE_WORK
216 spin_unlock(&priv->rxlock);
217#else
218#ifdef MCPU_MAC_DEBUG
219 if ( loops == RX_DESC_NUM )
220 printk("Bad receive packet !\n");
221#endif // MCPU_MAC_DEBUG
222#endif // USE_SCHEDULE_WORK
223 return;
224 }
225#if 0 // mask by Victor Yu. 07-04-2005
226 if ( rxdesc->rxdes0.ubit.RxErr ||
227 rxdesc->rxdes0.ubit.CRCErr ||
228 rxdesc->rxdes0.ubit.Ftl ||
229 rxdesc->rxdes0.ubit.Runt ||
230 rxdesc->rxdes0.ubit.RxOddNb ) {
231#else // add by Victor Yu. 07-04-2005
232#if defined(CONFIG_VLAN_8021Q) || defined(CONFIG_VLAN_8021Q_MODULE)
233 if ( ui & (RX_ERR|CRC_ERR|RUNT|RX_ODD_NB) ) {
234#else
235 if ( ui & (RX_ERR|CRC_ERR|FTL|RUNT|RX_ODD_NB) ) {
236#endif
237#endif // 07-04-2005
238 dbg_printk("Ethernet receive packet error !\n");
239 priv->stats.rx_dropped++;
240 priv->stats.rx_errors++;
241 goto recv_finish;
242 }
243#if 0 // mask by Victor Yu. 07-04-2005
244 len = rxdesc->rxdes0.ubit.RecvFrameLen > RX_BUF_SIZE ? RX_BUF_SIZE : rxdesc->rxdes0.ubit.RecvFrameLen;
245#else // add by Victor Yu. 07-04-2005
246 len = ui & RFL_MASK;
247 if ( len > RX_BUF_SIZE )
248 len = RX_BUF_SIZE;
249#endif // 07-04-2005
250 skb = dev_alloc_skb(len+2);
251 if ( skb == NULL ) {
252 dbg_printk("Allocate memory fail !\n");
253 priv->stats.rx_dropped++;
254 goto recv_finish;
255 }
256 skb_reserve(skb, 2);
257 skb->dev = dev;
258 data = skb_put(skb, len);
259 dbg_printk("receive data pointer = 0x%x\n", (unsigned long)data);
260#if 0 // mask by Victor Yu. 07-04-2005
261 memcpy(data, rxdesc->rxdes2.virtRxBufBaseAddr, len);
262#else // add by Victor Yu. 07-04-2005
263 mywordcopy((void *)data, (void *)rxdesc->rxdes2.virtRxBufBaseAddr, len);
264#endif // 07-04-2005
265 skb->protocol = eth_type_trans(skb, dev);
266 netif_rx(skb);
267 priv->stats.rx_packets++;
268 priv->stats.rx_bytes += len;
269 if ( ui & MULTICAST_RXDES0 )
270 priv->stats.multicast++;
271 dbg_printk("Receive a good packet.\n");
272
273
274
275recv_finish:
276#if 0 // mask by Victor Yu. 07-04-2005
277 rxdesc->rxdes0.ui = 0;
278 rxdesc->rxdes0.ubit.RxDMAOwn = 1;
279 rxdesc->rxdes1.ubit.RxBufSize = RX_BUF_SIZE;
280#else // add by Victor Yu. 07-04-2005
281 rxdesc->rxdes0.ui = RXDMA_OWN;
282#endif // 07-04-2005
283 rxnow++;
284 rxnow &= RX_DESC_NUM_MASK;
285 priv->RxDescNow = rxnow;
286
287#ifdef USE_SCHEDULE_WORK
288 goto repeat_recv;
289#else // USE_SCHEDULE_WORK
290 if ( loops-- > 0 )
291 goto repeat_recv;
292#endif // USE_SCHEDULE_WORK
293
294#ifdef USE_SCHEDULE_WORK
295 spin_unlock(&priv->rxlock);
296#endif // USE_SCHEDULE_WORK
297
298
299}
300
301
302static void mcpu_mac_free_memory(struct net_device *dev)
303{
304 mcpu_mac_priv_t *priv=(mcpu_mac_priv_t *)dev->priv;
305
306 if ( priv->virtTxDescBaseAddr )
307 dma_free_coherent(NULL, sizeof(tx_desc_t)*TX_DESC_NUM, priv->virtTxDescBaseAddr, priv->phyTxDescBaseAddr);
308 if ( priv->virtRxDescBaseAddr )
309 dma_free_coherent(NULL, sizeof(rx_desc_t)*RX_DESC_NUM, priv->virtRxDescBaseAddr, priv->phyRxDescBaseAddr);
310 if ( priv->virtTxBufBaseAddr )
311 dma_free_coherent(NULL, TX_BUF_SIZE*TX_DESC_NUM, priv->virtTxBufBaseAddr, priv->phyTxBufBaseAddr);
312 if ( priv->virtRxBufBaseAddr )
313 dma_free_coherent(NULL, RX_BUF_SIZE*RX_DESC_NUM, priv->virtRxBufBaseAddr, priv->phyRxBufBaseAddr);
314}
315
316static void mcpu_mac_setup_desc_ring(struct net_device *dev)
317{
318 mcpu_mac_priv_t *priv=(mcpu_mac_priv_t *)dev->priv;
319 int i;
320 tx_desc_t *txdesc;
321 rx_desc_t *rxdesc;
322 unsigned char *virtbuf;
323 unsigned int phybuf;
324
325 virtbuf = priv->virtTxBufBaseAddr;
326 phybuf = priv->phyTxBufBaseAddr;
327 for ( i=0; i<TX_DESC_NUM; i++, virtbuf+=TX_BUF_SIZE, phybuf+=TX_BUF_SIZE ) {
328 txdesc = &priv->virtTxDescBaseAddr[i];
329 memset(txdesc, 0, sizeof(tx_desc_t));
330 txdesc->txdes2.phyTxBufBaseAddr = phybuf;
331 txdesc->txdes2.virtTxBufBaseAddr = virtbuf;
332 }
333 priv->virtTxDescBaseAddr[TX_DESC_NUM-1].txdes1.ubit.Edotr = 1;
334
335 virtbuf = priv->virtRxBufBaseAddr;
336 phybuf = priv->phyRxBufBaseAddr;
337 for ( i=0; i<RX_DESC_NUM; i++, virtbuf+=RX_BUF_SIZE, phybuf+=RX_BUF_SIZE ) {
338 rxdesc = &priv->virtRxDescBaseAddr[i];
339 memset(rxdesc, 0, sizeof(rx_desc_t));
340 rxdesc->rxdes0.ubit.RxDMAOwn = 1;
341 rxdesc->rxdes1.ubit.RxBufSize = RX_BUF_SIZE;
342 rxdesc->rxdes2.phyRxBufBaseAddr = phybuf;
343 rxdesc->rxdes2.virtRxBufBaseAddr = virtbuf;
344 }
345 priv->virtRxDescBaseAddr[RX_DESC_NUM-1].rxdes1.ubit.Edorr = 1;
346 //dbg_printk("First Rx desc des0=0x%x, des1=%x\n", priv->virtRxDescBaseAddr[0].rxdes0.ui, priv->virtRxDescBaseAddr[0].rxdes1.ui);
347
348 priv->TxDescNow = priv->RxDescNow = 0;
349
350 // reset the MAC controler Tx/Rx desciptor base address
351 outl(priv->phyTxDescBaseAddr, dev->base_addr+TXR_BADR_REG_OFFSET);
352 outl(priv->phyRxDescBaseAddr, dev->base_addr+RXR_BADR_REG_OFFSET);
353#if 0
354 dbg_printk("Tx/Rx desc phy=0x%x,0x%x, virt=0x%x,0x%x\n", priv->phyTxDescBaseAddr, priv->phyRxDescBaseAddr, (unsigned int)priv->virtTxDescBaseAddr, (unsigned int)priv->virtRxDescBaseAddr);
355 dbg_printk("set Tx desc base address=0x%x, Rx=0x%x\n", inl(dev->base_addr+TXR_BADR_REG_OFFSET), inl(dev->base_addr+RXR_BADR_REG_OFFSET));
356#endif
357}
358
359static void mcpu_mac_reset(struct net_device *dev)
360{
361 unsigned int reg=dev->base_addr+MACCR_REG_OFFSET;
362
363 outl(SW_RST, reg); // software reset
364 while ( inl(reg) & SW_RST ) mdelay(10);
365 // maybe we need to disable the all interrupt
366 outl(0, dev->base_addr+IMR_REG_OFFSET);
367// ((mcpu_mac_priv_t *)dev->priv)->maccr = RX_BROADPKT | FULLDUP | CRC_APD;
368#if defined(CONFIG_VLAN_8021Q) || defined(CONFIG_VLAN_8021Q_MODULE) //johnson modify for 802.1Q support 2008-11-14
369 ((mcpu_mac_priv_t *)dev->priv)->maccr = RX_BROADPKT | ENRX_IN_HALFTX | CRC_APD | RX_FTL;
370#else
371 ((mcpu_mac_priv_t *)dev->priv)->maccr = RX_BROADPKT | ENRX_IN_HALFTX | CRC_APD;
372#endif
373}
374
375static void mcpu_mac_set_mac_address(unsigned int base, unsigned char *macaddr)
376{
377 unsigned int val;
378
379 val = (((u32)macaddr[0] << 8) &0xff00) | ((u32)macaddr[1] & 0xff);
380 outl(val, base);
381 val = (((u32)macaddr[2]<<24) & 0xff000000) |
382 (((u32)macaddr[3]<<16) & 0x00ff0000) |
383 (((u32)macaddr[4]<<8) & 0x0000ff00) |
384 (((u32)macaddr[5]) & 0x000000ff);
385 outl(val, base+4);
386}
387
388#ifdef MCPU_MAC_DEBUG // add by Victor Yu. 03-14-2006
389static void mcpu_mac_get_mac_address(unsigned int base, unsigned char *macaddr)
390{
391 unsigned int val;
392
393 val = inl(base);
394 macaddr[0] = (val >> 8) & 0xff;
395 macaddr[1] = val & 0xff;
396 val = inl(base+4);
397 macaddr[2] = (val >> 24) & 0xff;
398 macaddr[3] = (val >> 16) & 0xff;
399 macaddr[4] = (val >> 8) & 0xff;
400 macaddr[5] = val & 0xff;
401}
402#endif
403
404static void mcpu_mac_enable(struct net_device *dev)
405{
406 mcpu_mac_priv_t *priv=(mcpu_mac_priv_t *)dev->priv;
407 unsigned int base=dev->base_addr;
408
409 outl(0x00001010, base+ITC_REG_OFFSET);
410 outl(0x00000001, base+APTC_REG_OFFSET);
411 outl(0x00000390, base+DBLAC_REG_OFFSET);
412#ifdef MCPU_MAC_DEBUG
413 outl(RPKT_FINISH_M|NORXBUF_M|AHB_ERR_M, base+IMR_REG_OFFSET);
414#else
415 outl(RPKT_FINISH_M, base+IMR_REG_OFFSET);
416#endif
417 priv->maccr |= (RCV_EN | XMT_EN | RDMA_EN | XDMA_EN);
418 outl(priv->maccr, base+MACCR_REG_OFFSET);
419}
420
421static void mcpu_mac_tx_timeout(struct net_device *dev)
422{
423 mcpu_mac_priv_t *priv=(mcpu_mac_priv_t *)dev->priv;
424 unsigned long flags;
425
426 dbg_printk("mcpu_mac_tx_timeout test01\n");
427 save_flags(flags);
428 cli();
429#ifdef USE_SCHEDULE_WORK
430 spin_lock(&priv->rxlock);
431#endif
432 spin_lock(&priv->txlock);
433 mcpu_mac_reset(dev);
434 mcpu_mac_set_mac_address(dev->base_addr+MAC_MADR_REG_OFFSET, dev->dev_addr);
435 mcpu_mac_setup_desc_ring(dev);
436 mcpu_mac_enable(dev);
437 spin_unlock(&priv->txlock);
438#ifdef USE_SCHEDULE_WORK
439 spin_unlock(&priv->rxlock);
440#endif
441 restore_flags(flags);
442 netif_wake_queue(dev);
443 dev->trans_start = jiffies;
444}
445
446static int mcpu_mac_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
447{
448 mcpu_mac_priv_t *priv=(mcpu_mac_priv_t *)dev->priv;
449 tx_desc_t *txdesc;
450 int len;
451 int txnow=priv->TxDescNow;
452
453 dbg_printk("mcpu_mac_hard_start_xmit test01\n");
454 spin_lock(&priv->txlock);
455
456 // first check the Tx buffer is enough or not
457 txdesc = &priv->virtTxDescBaseAddr[txnow];
458 if ( txdesc->txdes0.ubit.TxDMAOwn ) {
459 dbg_printk("No Tx space to transmit the packet !\n");
460 priv->stats.tx_dropped++;
461 goto xmit_final;
462 }
463
464 // fill the data
465#if 0 // mask by Victor Yu. 07-04-2005
466 len = skb->len < ETH_ZLEN ? ETH_ZLEN : skb->len;
467 len = len > TX_BUF_SIZE ? TX_BUF_SIZE : len;
468#else // add by Victor Yu. 07-04-2005
469 len = skb->len > TX_BUF_SIZE ? TX_BUF_SIZE : skb->len;
470#endif
471#if 0 // mask by Victor Yu. 07-04-2005
472 memcpy(txdesc->txdes2.virtTxBufBaseAddr, skb->data, len);
473#else // add by Victor Yu. 07-04-2005
474 mywordcopy((void *)txdesc->txdes2.virtTxBufBaseAddr, (void *)skb->data, len);
475#endif
476 dbg_printk("transmit data pointer = 0x%x\n", (unsigned long)skb->data);
477#if 1 // add by Victor Yu. 07-04-2005
478 if ( skb->len < ETH_ZLEN ) {
479 memset(&txdesc->txdes2.virtTxBufBaseAddr[skb->len], 0, ETH_ZLEN-skb->len);
480 len = ETH_ZLEN;
481 }
482#endif
483 txdesc->txdes1.ubit.Lts = 1;
484 txdesc->txdes1.ubit.Fts = 1;
485 txdesc->txdes1.ubit.Tx2fic = 0;
486 txdesc->txdes1.ubit.Txic = 0;
487 txdesc->txdes1.ubit.TxBufSize = len;
488#if 0 // mask by Victor Yu. 07-04-2005
489 txdesc->txdes0.ui = 0;
490 txdesc->txdes0.ubit.TxDMAOwn = 1;
491#else // add by Victor Yu. 07-04-2005
492 txdesc->txdes0.ui = TXDMA_OWN;
493#endif
494
495 outl(0xffffffff, dev->base_addr+TXPD_REG_OFFSET); // start to send packet
496#if 0
497 dbg_printk("TxDescNow=%d, address=0x%x, des0=0x%x, des1=0x%x\n", priv->TxDescNow, (unsigned int)&priv->virtTxDescBaseAddr[priv->TxDescNow], txdesc->txdes0.ui, txdesc->txdes1.ui);
498 dbg_printk("Buffer phy address=0x%x, virt=0x%x\n", txdesc->txdes2.phyTxBufBaseAddr, (unsigned int)txdesc->txdes2.virtTxBufBaseAddr);
499 dbg_printk("TxDescNow-1=%d, address=0x%x, des0=0x%x\n", (priv->TxDescNow-1)&TX_DESC_NUM_MASK, (unsigned int)&priv->virtTxDescBaseAddr[(priv->TxDescNow-1)&TX_DESC_NUM_MASK], priv->virtTxDescBaseAddr[(priv->TxDescNow-1)&TX_DESC_NUM_MASK].txdes0.ui);
500#endif
501 txnow++;
502 txnow &= TX_DESC_NUM_MASK;
503 priv->TxDescNow = txnow;
504 dev->trans_start = jiffies;
505 priv->stats.tx_packets++;
506 priv->stats.tx_bytes += len;
507
508xmit_final:
509 spin_unlock(&priv->txlock);
510 dev_kfree_skb_any(skb);
511
512 return 0;
513}
514
515static int mcpu_mac_open(struct net_device *dev)
516{
517 mcpu_mac_priv_t *priv=(mcpu_mac_priv_t *)dev->priv;
518 unsigned long flags;
519
520 dbg_printk("mcpu_mac_open test01\n");
521
522 save_flags(flags);
523 cli();
524#ifdef USE_SCHEDULE_WORK
525 spin_lock(&priv->rxlock);
526#endif
527 spin_lock(&priv->txlock);
528 mcpu_mac_reset(dev);
529 mcpu_mac_set_mac_address(dev->base_addr+MAC_MADR_REG_OFFSET, dev->dev_addr);
530 mcpu_mac_setup_desc_ring(dev);
531 mcpu_mac_enable(dev);
532 spin_unlock(&priv->txlock);
533#ifdef USE_SCHEDULE_WORK
534 spin_unlock(&priv->rxlock);
535#endif
536 restore_flags(flags);
537 netif_start_queue(dev);
538 dbg_printk("IMR=0x%x, MACCR=0x%x\n", inl(dev->base_addr+IMR_REG_OFFSET), inl(dev->base_addr+MACCR_REG_OFFSET));
539#ifdef MCPU_MAC_DEBUG
540 {
541 unsigned char macaddr[6];
542 int i;
543 mcpu_mac_get_mac_address(dev->base_addr+MAC_MADR_REG_OFFSET, macaddr);
544 printk("Get MAC address = ");
545 for ( i=0; i<6; i++ )
546 printk("%02X ", macaddr[i]);
547 printk("\n");
548 }
549#endif
550
551 return 0;
552}
553
554static int mcpu_mac_stop(struct net_device *dev)
555{
556 mcpu_mac_priv_t *priv=(mcpu_mac_priv_t *)dev->priv;
557 unsigned long flags;
558
559 dbg_printk("mcpu_mac_stop test01\n");
560 netif_stop_queue(dev);
561 save_flags(flags);
562 cli();
563#ifdef USE_SCHEDULE_WORK
564 spin_lock(&priv->rxlock);
565#endif
566 spin_lock(&priv->txlock);
567 outl(0, dev->base_addr+IMR_REG_OFFSET); // disable all interrupt
568 outl(0, dev->base_addr+MACCR_REG_OFFSET); // disable all function
569 spin_unlock(&priv->txlock);
570#ifdef USE_SCHEDULE_WORK
571 spin_unlock(&priv->rxlock);
572#endif
573 restore_flags(flags);
574
575 return 0;
576}
577
578static struct net_device_stats *mcpu_mac_get_stats(struct net_device *dev)
579{
580 mcpu_mac_priv_t *priv=(mcpu_mac_priv_t *)dev->priv;
581
582 dbg_printk("mcpu_mac_get_stats test01\n");
583#if 0
584 {
585 unsigned int base=dev->base_addr;
586 int desc=priv->RxDescNow;
587 dbg_printk("RxDescNow=%d, desc phy=0x%x, virt=0x%x, buf phy=0x%x, virt=0x%x\n", desc, priv->phyRxDescBaseAddr+(desc*sizeof(rx_desc_t)), (unsigned int)&priv->virtRxDescBaseAddr[desc], priv->virtRxDescBaseAddr[desc].rxdes2.phyRxBufBaseAddr, (unsigned int)priv->virtRxDescBaseAddr[desc].rxdes2.virtRxBufBaseAddr);
588 dbg_printk("Now Rx desc des0=0x%x, des1=0x%x\n", priv->virtRxDescBaseAddr[desc].rxdes0.ui, priv->virtRxDescBaseAddr[desc].rxdes1.ui);
589 desc++;
590 desc &= RX_DESC_NUM_MASK;
591 dbg_printk("Next RxDescNow=%d, desc phy=0x%x, virt=0x%x, buf phy=0x%x, virt=0x%x\n", desc, priv->phyRxDescBaseAddr+(desc*sizeof(rx_desc_t)), (unsigned int)&priv->virtRxDescBaseAddr[desc], priv->virtRxDescBaseAddr[desc].rxdes2.phyRxBufBaseAddr, (unsigned int)priv->virtRxDescBaseAddr[desc].rxdes2.virtRxBufBaseAddr);
592 dbg_printk("Next Now Rx desc des0=0x%x, des1=0x%x\n", priv->virtRxDescBaseAddr[desc].rxdes0.ui, priv->virtRxDescBaseAddr[desc].rxdes1.ui);
593 printk("TX_MCOL_TX_SCOL register = 0x%x\n", inl(base+TX_MCOL_TX_SCOL_REG_OFFSET));
594 printk("RPF_AEP register = 0x%x\n", inl(base+RPF_AEP_REG_OFFSET));
595 printk("XM_PG register = 0x%x\n", inl(base+XM_PG_REG_OFFSET));
596 printk("RUNT_CNT_TLCC register = 0x%x\n", inl(base+RUNT_CNT_TLCC_REG_OFFSET));
597 printk("CRCER_CNT_FTL_CNT register = 0x%x\n", inl(base+CRCER_CNT_FTL_CNT_REG_OFFSET));
598 printk("RLC_RCC register = 0x%x\n", inl(base+RLC_RCC_REG_OFFSET));
599 printk("BROC register = 0x%x\n", inl(base+BROC_REG_OFFSET));
600 printk("MUCLA register = 0x%x\n", inl(base+MULCA_REG_OFFSET));
601 printk("RP register = 0x%x\n", inl(base+RP_REG_OFFSET));
602 printk("XP register = 0x%x\n", inl(base+XP_REG_OFFSET));
603 }
604#endif
605
606 return &priv->stats;
607}
608
609
610static irqreturn_t mcpu_mac_interrupt(int irq, void *dev_id, struct pt_regs *regs)
611{
612 struct net_device *dev=(struct net_device *)dev_id;
613 unsigned int ists;
614#ifdef USE_SCHEDULE_WORK
615 mcpu_mac_priv_t *priv=(mcpu_mac_priv_t *)dev->priv;
616#endif
617
618
619 //dbg_printk("mcpu_mac_interrupt test01\n");
620 ists = inl(dev->base_addr+ISR_REG_OFFSET);
621 if ( ists & RPKT_FINISH ) {
622#ifdef USE_SCHEDULE_WORK
623 schedule_work(&priv->rqueue);
624#else
625 mcpu_mac_recv((void *)dev);
626#endif
627 } else {
628#ifdef MCPU_MAC_DEBUG
629 if ( ists & NORXBUF ) {
630 printk("Receiver no Rx buffer interrupt\n");
631 outl(inl(dev->base_addr+IMR_REG_OFFSET)&~NORXBUF_M, dev->base_addr+IMR_REG_OFFSET);
632 //return IRQ_HANDLED;
633 }
634 if ( ists & AHB_ERR ) {
635 printk("Receiver AHB error interrupt.\n");
636 //return IRQ_HANDLED;
637 }
638#endif
639 //return IRQ_NONE;
640 }
641
642 return IRQ_HANDLED;
643}
644
645static int mcpu_mac_init(struct net_device *dev)
646{
647 mcpu_mac_priv_t *priv=(mcpu_mac_priv_t *)dev->priv;
648
649 dbg_printk("mcpu_mac_init test01\n");
650
651 // first initialize the private variable to zero
652 memset((void *)priv, 0, sizeof(mcpu_mac_priv_t));
653 spin_lock_init(&priv->txlock);
654
655#ifdef USE_SCHEDULE_WORK
656
657//#if 1 // add by Victor Yu. 07-04-2005
658 spin_lock_init(&priv->rxlock);
659 INIT_WORK(&priv->rqueue, &mcpu_mac_recv, (void *)dev);
660#endif
661
662 // allocate the descriptor and buffer memory
663 priv->virtTxDescBaseAddr = (tx_desc_t *)dma_alloc_coherent(NULL, sizeof(tx_desc_t)*TX_DESC_NUM, (dma_addr_t *)&priv->phyTxDescBaseAddr, GFP_DMA|GFP_KERNEL);
664 if ( priv->virtTxDescBaseAddr == NULL || (priv->phyTxDescBaseAddr & 0x0f) ) {
665 dbg_printk("Allocate the Tx descriptor memory fail !\n");
666 goto init_fail;
667 }
668 priv->virtRxDescBaseAddr = (rx_desc_t *)dma_alloc_coherent(NULL, sizeof(rx_desc_t)*RX_DESC_NUM, (dma_addr_t *)&priv->phyRxDescBaseAddr, GFP_DMA|GFP_KERNEL);
669 if ( priv->virtRxDescBaseAddr == NULL || (priv->phyRxDescBaseAddr & 0x0f) ) {
670 dbg_printk("Allocate the Rx descriptor memory fail !\n");
671 goto init_fail;
672 }
673 priv->virtTxBufBaseAddr = (unsigned char *)dma_alloc_coherent(NULL, TX_BUF_SIZE*TX_DESC_NUM, (dma_addr_t *)&priv->phyTxBufBaseAddr, GFP_DMA|GFP_KERNEL);
674 if ( priv->virtTxBufBaseAddr == NULL || (priv->phyTxBufBaseAddr & 0x03) ) {
675 dbg_printk("Allocate the Tx buffer memory fail !\n");
676 goto init_fail;
677 }
678 priv->virtRxBufBaseAddr = (unsigned char *)dma_alloc_coherent(NULL, RX_BUF_SIZE*RX_DESC_NUM, (dma_addr_t *)&priv->phyRxBufBaseAddr, GFP_DMA|GFP_KERNEL);
679 if ( priv->virtRxBufBaseAddr == NULL || (priv->phyRxBufBaseAddr & 0x03) ) {
680 dbg_printk("Allocate the Rx buffer memory fail !\n");
681 goto init_fail;
682 }
683
684 // setup the thernet basic
685 ether_setup(dev);
686
687 // reset the MAC
688 mcpu_mac_reset(dev);
689 mcpu_mac_setup_desc_ring(dev);
690
691 // we need to get the MAC address from the hardware and set to the device
692#ifdef CONFIG_ARCH_CPE
693dev->dev_addr[0] = 0x00;
694dev->dev_addr[1] = 0x90;
695dev->dev_addr[2] = 0xE8;
696dev->dev_addr[3] = 0x72;
697dev->dev_addr[4] = 0x20;
698dev->dev_addr[5] = 0x01;
699#endif // CONFIG_ARCH_CPE
700#ifdef CONFIG_ARCH_MOXACPU
701{
702#include <linux/mtd/mtd.h>
703 struct mtd_info *mtd;
704 int len;
705 mtd = get_mtd_device(NULL, 0);
706 if ( priv == (void *)&mcpu_mac_priv ) { // LAN 1
707 if ( mtd == NULL ) {
708#if 0 // mask by Victor Yu. 03-21-2006
709 dev->dev_addr[0] = 0x00;
710 dev->dev_addr[1] = 0x90;
711 dev->dev_addr[2] = 0xe8;
712 dev->dev_addr[3] = 0x10;
713 dev->dev_addr[4] = 0x02;
714 dev->dev_addr[5] = 0x40;
715#else // add by Victor Yu. 021-2006
716#if ( defined CONFIG_ARCH_W341 ) || ( defined CONFIG_ARCH_W345 ) || ( defined CONFIG_ARCH_W345_IMP1 ) || ( defined CONFIG_ARCH_UC_7112_LX_PLUS ) || ( defined CONFIG_ARCH_W311 ) || ( defined CONFIG_ARCH_W321 ) || ( defined CONFIG_ARCH_W315 ) || ( defined CONFIG_ARCH_W325 )
717 memcpy(dev->dev_addr, (char *)(CPE_FLASH_VA_BASE+0x50), 6);
718#elif ( defined CONFIG_ARCH_IA240 ) || ( defined CONFIG_ARCH_IA241 )
719 memcpy(dev->dev_addr, (char *)(CPE_FLASH_VA_BASE+0x56), 6);
720
721#endif
722
723#endif
724 } else {
725#if ( defined CONFIG_ARCH_W341 ) || ( defined CONFIG_ARCH_W345 ) || ( defined CONFIG_ARCH_W345_IMP1 ) || ( defined CONFIG_ARCH_UC_7112_LX_PLUS ) || ( defined CONFIG_ARCH_W311 ) || ( defined CONFIG_ARCH_W321 ) || ( defined CONFIG_ARCH_W315 ) || ( defined CONFIG_ARCH_W325 )
726
727 mtd->read(mtd, 0x50, 6, &len, dev->dev_addr);
728#elif ( defined CONFIG_ARCH_IA240 ) || ( defined CONFIG_ARCH_IA241 )
729 mtd->read(mtd, 0x56, 6, &len, dev->dev_addr);
730
731#endif
732
733 }
734 } else { // LAN2
735 if ( mtd == NULL ) {
736#if 0 // mask by Victor Yu. 03-21-2006
737 dev->dev_addr[0] = 0x00;
738 dev->dev_addr[1] = 0x90;
739 dev->dev_addr[2] = 0xe8;
740 dev->dev_addr[3] = 0x10;
741 dev->dev_addr[4] = 0x02;
742 dev->dev_addr[5] = 0x41;
743#else // add by Victor Yu. 03-21-2006
744
745#if ( defined CONFIG_ARCH_UC_7112_LX_PLUS )
746 memcpy(dev->dev_addr, (char *)(CPE_FLASH_VA_BASE+0x56), 6);
747#elif ( defined CONFIG_ARCH_IA240 ) || ( defined CONFIG_ARCH_IA241 )
748 memcpy(dev->dev_addr, (char *)(CPE_FLASH_VA_BASE+0x50), 6);
749#endif
750
751#endif
752
753 } else {
754#if ( defined CONFIG_ARCH_UC_7112_LX_PLUS )
755 mtd->read(mtd, 0x56, 6, &len, dev->dev_addr);
756#elif ( defined CONFIG_ARCH_IA240 ) || ( defined CONFIG_ARCH_IA241 )
757 mtd->read(mtd, 0x50, 6, &len, dev->dev_addr);
758#endif
759 }
760 }
761}
762#endif // CONFIG_ARCH_MOXACPU
763
764 // setup the low lever interrupt for Moxa CPU
765#include <asm/arch/cpe_int.h>
766 cpe_int_set_irq(dev->irq, LEVEL, H_ACTIVE);
767 if ( request_irq(dev->irq, &mcpu_mac_interrupt, SA_INTERRUPT, dev->name, dev) ) {
768 dbg_printk("Request interrupt service fail !\n");
769 goto init_fail;
770 }
771
772 return 0;
773
774init_fail:
775 mcpu_mac_free_memory(dev);
776 return -ENOMEM;
777}
778
779#if 1 // Add by Jared 12-04-2008
780
781#include <linux/ethtool.h>
782#include <linux/mii.h>
783
784#define PHY_CNTL_REG 0x00
785#define PHY_STATUS_REG 0x01
786#define PHY_ID_REG1 0x02
787#define PHY_ID_REG2 0x03
788#define PHY_ANA_REG 0x04
789#define PHY_ANLPAR_REG 0x05
790#define PHY_ANE_REG 0x06
791#define PHY_ECNTL_REG1 0x10
792#define PHY_QPDS_REG 0x11
793#define PHY_10BOP_REG 0x12
794#define PHY_ECNTL_REG2 0x13
795/* PHY Status register */
796#define AN_COMPLETE 0x0020
797#define Link_Status 0x0004
798//FTMAC100 register definition => 90/94: PHY register
799#define FTMAC100_REG_PHY_WRITE 0x08000000
800#define FTMAC100_REG_PHY_READ 0x04000000
801
802static DECLARE_MUTEX(miiAccessMutex);
803
804int flib_FTMAC100_PHY_Read_Waiting(struct net_device *dev) {
805 u32 wResult;
806 unsigned long t;
807
808 for(t = jiffies;;) {
809 if((jiffies - t) > (HZ/100) ) {
810 printk("<1>%s[%d]timeout\n",__FUNCTION__,__LINE__);
811 return (-1);
812 }
813 wResult = inl(dev->base_addr+PHYCR_REG_OFFSET);
814 if( (wResult & FTMAC100_REG_PHY_READ) == 0 )
815 break;
816 }
817 return 0;
818}
819
820int flib_FTMAC100_PHY_Write_Waiting(struct net_device *dev) {
821 u32 wResult;
822 unsigned long t;
823
824 for(t = jiffies;;) {
825 if((jiffies - t) > (HZ/100) ) {
826 printk("<1>%s[%d]\n",__FUNCTION__,__LINE__);
827 return (-1);
828 }
829 wResult = inl(dev->base_addr+PHYCR_REG_OFFSET);
830 if( (wResult & FTMAC100_REG_PHY_WRITE) == 0 )
831 break;
832 }
833 return 0;
834}
835
836u32 PhyMiiReadRtn (struct net_device *dev, u8 phyAddr, u8 phyReg, u16 *value) {
837 u32 dwTemp;
838
839 dwTemp= (phyAddr<<16) | ((phyReg & 0x1f) << 21) | FTMAC100_REG_PHY_READ;
840 outl(dwTemp, dev->base_addr + PHYCR_REG_OFFSET);
841
842 if(flib_FTMAC100_PHY_Read_Waiting(dev) != 0){
843 printk("<1>%s[%d]\n",__FUNCTION__,__LINE__);
844 return (-1);
845 }
846
847 *value = inw(dev->base_addr + PHYCR_REG_OFFSET);
848
849 return 0;
850}
851
852u32 PhyMiiWriteRtn (struct net_device *dev, u8 phyAddr, u8 phyReg, u16 value) {
853 u32 dwTemp, miiTimeout;
854
855 dwTemp = (phyAddr<<16) | ((phyReg & 0x1f) << 21) | FTMAC100_REG_PHY_WRITE;
856 outl(value, dev->base_addr + PHYWDATA_REG_OFFSET);
857 udelay(10) ;
858
859 if(flib_FTMAC100_PHY_Write_Waiting(dev) != 0){
860 printk("<1>%s[%d]\n",__FUNCTION__,__LINE__);
861 return (-1);
862 }
863
864 for(miiTimeout=10; miiTimeout>0; miiTimeout-- ) {
865 set_current_state(TASK_INTERRUPTIBLE);
866 schedule_timeout( (1*HZ)/1000 );
867 }
868
869 outl(dwTemp, dev->base_addr + PHYCR_REG_OFFSET);
870
871 if(flib_FTMAC100_PHY_Read_Waiting(dev) != 0){
872 printk("<1>%s[%d]\n",__FUNCTION__,__LINE__);
873 return (-2);
874 }
875
876 for(miiTimeout=10; miiTimeout>0; miiTimeout-- ) {
877 set_current_state(TASK_INTERRUPTIBLE);
878 schedule_timeout( (1*HZ)/1000 );
879 }
880
881 return 0;
882}
883
884#include <linux/ethtool.h>
885static int netdev_ethtool_ioctl(struct net_device *dev, void *useraddr)
886{
887 u32 dwTemp;
888 int ethcmd, res = 0;
889
890 if (copy_from_user (&ethcmd, useraddr, sizeof (ethcmd)))
891 return -EFAULT;
892
893 switch (ethcmd) {
894 case ETHTOOL_GLINK: {
895 struct ethtool_value edata = {ETHTOOL_GLINK};
896
897 dwTemp= (1<<16) | ((PHY_STATUS_REG & 0x1f) << 21) | FTMAC100_REG_PHY_READ;
898 outl(dwTemp, dev->base_addr + PHYCR_REG_OFFSET);
899 if(flib_FTMAC100_PHY_Read_Waiting(dev) != 0){
900 res = -1;
901 }
902 dwTemp = inw(dev->base_addr + PHYCR_REG_OFFSET);
903#if 0
904 printk("%s[%d]ETHTOOL_GLINK 0x%x-",__FUNCTION__,__LINE__, dwTemp) ;
905
906 dwTemp= (1<<16) | ((PHY_STATUS_REG & 0x1f) << 21) | FTMAC100_REG_PHY_READ;
907 outl(dwTemp, dev->base_addr + PHYCR_REG_OFFSET);
908 if(flib_FTMAC100_PHY_Read_Waiting(dev) != 0){
909 res = -1;
910 }
911 dwTemp = inw(dev->base_addr + PHYCR_REG_OFFSET);
912 printk("%s[%d]ETHTOOL_GLINK 0x%x-",__FUNCTION__,__LINE__, dwTemp) ;
913#endif
914 if ( (dwTemp & Link_Status) == Link_Status)
915 edata.data= 1;
916 else
917 edata.data= 0;
918
919 if (copy_to_user( useraddr, &edata, sizeof(edata)))
920 res= -EFAULT;
921
922 return res;
923 }
924
925 default:
926 return -EOPNOTSUPP;
927 }
928}
929
930static int mcpu_do_dev_ioctl(struct net_device *dev, struct ifreq *req, int cmd)
931{
932 struct mii_ioctl_data *data = (struct mii_ioctl_data *) & req->ifr_data;
933 int res=0;
934
935 switch (cmd)
936 {
937 /* Get address of MII PHY in use */
938 case SIOCGMIIPHY:
939 case SIOCDEVPRIVATE:
940#ifdef ONE_MII_Interface
941 if(port){
942 data->phy_id = 0x2;
943 }else{
944 data->phy_id = 0x10;
945 }
946#else
947 data->phy_id = 1;
948#endif
949 break;
950 /* Read MII PHY register */
951 case SIOCGMIIREG:
952 case SIOCDEVPRIVATE+1:
953 down (&miiAccessMutex); /* lock the MII register access mutex */
954 if ((res = PhyMiiReadRtn (dev, data->phy_id, data->reg_num, &data->val_out)))
955 {
956 printk("Error reading MII reg %d on phy %d\n",
957 data->reg_num, data->phy_id);
958 res = -1;
959 }
960 up (&miiAccessMutex); /* release the MII register access mutex */
961 break;
962 /* Write MII PHY register */
963 case SIOCSMIIREG:
964 case SIOCDEVPRIVATE+2:
965 down (&miiAccessMutex); /* lock the MII register access mutex */
966 if ((res = PhyMiiWriteRtn (dev, data->phy_id, data->reg_num, data->val_in)))
967 {
968 printk("Error writing MII reg %d on phy %d\n",
969 data->reg_num, data->phy_id);
970 res = -1;
971 }
972 up (&miiAccessMutex); /* release the MII register access mutex */
973 break;
974 case SIOCETHTOOL:
975 return netdev_ethtool_ioctl(dev, req->ifr_data);
976 default:
977 res = -EOPNOTSUPP;
978 }
979
980 return res;
981}
982
983#endif // end of add by Jared 12-04-2008
984
985static struct net_device mcpu_mac_dev = {
986#ifdef CONFIG_ARCH_MOXACPU
987
988#if ( defined CONFIG_ARCH_W341 ) || ( defined CONFIG_ARCH_W345 ) || ( defined CONFIG_ARCH_W345_IMP1 ) || ( defined CONFIG_ARCH_UC_7112_LX_PLUS ) || ( defined CONFIG_ARCH_W311 ) || ( defined CONFIG_ARCH_W321 ) || ( defined CONFIG_ARCH_W315 ) || ( defined CONFIG_ARCH_W325 )
989 .name = "eth0",
990#elif ( defined CONFIG_ARCH_IA240 ) || ( defined CONFIG_ARCH_IA241 )
991 .name = "eth1",
992#endif
993
994#endif
995 .base_addr = IO_ADDRESS(CPE_FTMAC_BASE),
996 .irq = IRQ_MAC,
997 .init = &mcpu_mac_init,
998 .get_stats = &mcpu_mac_get_stats,
999 .open = &mcpu_mac_open,
1000 .stop = &mcpu_mac_stop,
1001 .hard_start_xmit= &mcpu_mac_hard_start_xmit,
1002 .priv = (void *)&mcpu_mac_priv,
1003 .tx_timeout = &mcpu_mac_tx_timeout,
1004#ifdef HAVE_MULTICAST
1005 .set_multicast_list = &mcpu_mac_set_multicast_list,
1006#endif
1007#if 1 // Add by Jared 12-04-2008
1008 .do_ioctl = mcpu_do_dev_ioctl,
1009#endif // end of add by Jared 12-04-2008
1010};
1011
1012#ifdef CONFIG_ARCH_MOXACPU
1013
1014
1015#if ( defined CONFIG_ARCH_IA240 ) || ( defined CONFIG_ARCH_IA241 ) || ( defined CONFIG_ARCH_UC_7112_LX_PLUS )
1016static struct net_device mcpu_mac_dev2 = {
1017#if ( defined CONFIG_ARCH_IA240 ) || ( defined CONFIG_ARCH_IA241 )
1018 .name = "eth0",
1019#elif ( defined CONFIG_ARCH_UC_7112_LX_PLUS )
1020 .name = "eth1",
1021#endif
1022 .base_addr = IO_ADDRESS(CPE_FTMAC2_BASE),
1023 .irq = IRQ_MAC2,
1024 .init = &mcpu_mac_init,
1025 .get_stats = &mcpu_mac_get_stats,
1026 .open = &mcpu_mac_open,
1027 .stop = &mcpu_mac_stop,
1028 .hard_start_xmit= &mcpu_mac_hard_start_xmit,
1029 .priv = (void *)&mcpu_mac_priv2,
1030 .tx_timeout = &mcpu_mac_tx_timeout,
1031#ifdef HAVE_MULTICAST
1032 .set_multicast_list = &mcpu_mac_set_multicast_list,
1033#endif
1034#if 1 // Add by Jared 12-04-2008
1035 .do_ioctl = mcpu_do_dev_ioctl,
1036#endif // end of add by Jared 12-04-2008
1037};
1038#endif
1039
1040#endif // CONFIG_ARCH_MOXACPU
1041
1042static int __init mcpu_mac_init_module(void)
1043{
1044 int ret;
1045 printk("Moxa CPU Ethernet Device Driver Version 1.0 load ");
1046 ret = register_netdev(&mcpu_mac_dev);
1047 if ( ret ) {
1048 printk("fail !\n");
1049 return ret;
1050 }
1051
1052#ifdef CONFIG_ARCH_MOXACPU
1053
1054
1055#if ( defined CONFIG_ARCH_IA240 ) || ( defined CONFIG_ARCH_IA241 ) || ( defined CONFIG_ARCH_UC_7112_LX_PLUS )
1056
1057 ret = register_netdev(&mcpu_mac_dev2);
1058 if ( ret ) {
1059 mcpu_mac_free_memory(&mcpu_mac_dev);
1060 free_irq(mcpu_mac_dev.irq, &mcpu_mac_dev);
1061 unregister_netdev(&mcpu_mac_dev);
1062 printk("fail !\n");
1063 return ret;
1064 }
1065#endif
1066
1067
1068#endif // CONFIG_ARCH_MOXACPU
1069
1070 printk("OK.\n");
1071
1072 return 0;
1073}
1074
1075static void __exit mcpu_mac_cleanup_module(void)
1076{
1077 printk("Moxa CPU Ethernet Device Driver unload.\n");
1078 mcpu_mac_free_memory(&mcpu_mac_dev);
1079 free_irq(mcpu_mac_dev.irq, &mcpu_mac_dev);
1080 unregister_netdev(&mcpu_mac_dev);
1081
1082#ifdef CONFIG_ARCH_MOXACPU
1083
1084#if ( defined CONFIG_ARCH_IA240 ) || ( defined CONFIG_ARCH_IA241 )|| ( defined CONFIG_ARCH_UC_7112_LX_PLUS )
1085 mcpu_mac_free_memory(&mcpu_mac_dev2);
1086 free_irq(mcpu_mac_dev2.irq, &mcpu_mac_dev2);
1087 unregister_netdev(&mcpu_mac_dev2);
1088#endif
1089
1090#endif // CONFIG_ARCH_MOXACPU
1091}
1092
1093module_init(mcpu_mac_init_module);
1094module_exit(mcpu_mac_cleanup_module);