]> git.kernelconcepts.de Git - karo-tx-uboot.git/blob - drivers/net/npe/npe.c
Merge branch 'u-boot-imx/master' into 'u-boot-arm/master'
[karo-tx-uboot.git] / drivers / net / npe / npe.c
1 /*
2  * (C) Copyright 2005-2006
3  * Stefan Roese, DENX Software Engineering, sr@denx.de.
4  *
5  * See file CREDITS for list of people who contributed to this
6  * project.
7  *
8  * This program is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU General Public License as
10  * published by the Free Software Foundation; either version 2 of
11  * the License, or (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program; if not, write to the Free Software
20  * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
21  * MA 02111-1307 USA
22  */
23
24 #if 0
25 #define DEBUG           /* define for debug output */
26 #endif
27
28 #include <config.h>
29 #include <common.h>
30 #include <net.h>
31 #include <miiphy.h>
32 #include <malloc.h>
33 #include <asm/processor.h>
34 #include <asm/arch-ixp/ixp425.h>
35
36 #include <IxOsal.h>
37 #include <IxEthAcc.h>
38 #include <IxEthDB.h>
39 #include <IxNpeDl.h>
40 #include <IxQMgr.h>
41 #include <IxNpeMh.h>
42 #include <ix_ossl.h>
43 #include <IxFeatureCtrl.h>
44
45 #include <npe.h>
46
47 static IxQMgrDispatcherFuncPtr qDispatcherFunc = NULL;
48 static int npe_exists[NPE_NUM_PORTS];
49 static int npe_used[NPE_NUM_PORTS];
50
51 /* A little extra so we can align to cacheline. */
52 static u8 npe_alloc_pool[NPE_MEM_POOL_SIZE + CONFIG_SYS_CACHELINE_SIZE - 1];
53 static u8 *npe_alloc_end;
54 static u8 *npe_alloc_free;
55
56 static void *npe_alloc(int size)
57 {
58         static int count = 0;
59         void *p = NULL;
60
61         size = (size + (CONFIG_SYS_CACHELINE_SIZE-1)) & ~(CONFIG_SYS_CACHELINE_SIZE-1);
62         count++;
63
64         if ((npe_alloc_free + size) < npe_alloc_end) {
65                 p = npe_alloc_free;
66                 npe_alloc_free += size;
67         } else {
68                 printf("npe_alloc: failed (count=%d, size=%d)!\n", count, size);
69         }
70         return p;
71 }
72
73 /* Not interrupt safe! */
74 static void mbuf_enqueue(IX_OSAL_MBUF **q, IX_OSAL_MBUF *new)
75 {
76         IX_OSAL_MBUF *m = *q;
77
78         IX_OSAL_MBUF_NEXT_PKT_IN_CHAIN_PTR(new) = NULL;
79
80         if (m) {
81                 while(IX_OSAL_MBUF_NEXT_PKT_IN_CHAIN_PTR(m))
82                         m = IX_OSAL_MBUF_NEXT_PKT_IN_CHAIN_PTR(m);
83                 IX_OSAL_MBUF_NEXT_PKT_IN_CHAIN_PTR(m) = new;
84         } else
85                 *q = new;
86 }
87
88 /* Not interrupt safe! */
89 static IX_OSAL_MBUF *mbuf_dequeue(IX_OSAL_MBUF **q)
90 {
91         IX_OSAL_MBUF *m = *q;
92         if (m)
93                 *q = IX_OSAL_MBUF_NEXT_PKT_IN_CHAIN_PTR(m);
94         return m;
95 }
96
97 static void reset_tx_mbufs(struct npe* p_npe)
98 {
99         IX_OSAL_MBUF *m;
100         int i;
101
102         p_npe->txQHead = NULL;
103
104         for (i = 0; i < CONFIG_DEVS_ETH_INTEL_NPE_MAX_TX_DESCRIPTORS; i++) {
105                 m = &p_npe->tx_mbufs[i];
106
107                 memset(m, 0, sizeof(*m));
108
109                 IX_OSAL_MBUF_MDATA(m) = (void *)&p_npe->tx_pkts[i * NPE_PKT_SIZE];
110                 IX_OSAL_MBUF_MLEN(m) = IX_OSAL_MBUF_PKT_LEN(m) = NPE_PKT_SIZE;
111                 mbuf_enqueue(&p_npe->txQHead, m);
112         }
113 }
114
115 static void reset_rx_mbufs(struct npe* p_npe)
116 {
117         IX_OSAL_MBUF *m;
118         int i;
119
120         p_npe->rxQHead = NULL;
121
122         HAL_DCACHE_INVALIDATE(p_npe->rx_pkts, NPE_PKT_SIZE *
123                               CONFIG_DEVS_ETH_INTEL_NPE_MAX_RX_DESCRIPTORS);
124
125         for (i = 0; i < CONFIG_DEVS_ETH_INTEL_NPE_MAX_RX_DESCRIPTORS; i++) {
126                 m = &p_npe->rx_mbufs[i];
127
128                 memset(m, 0, sizeof(*m));
129
130                 IX_OSAL_MBUF_MDATA(m) = (void *)&p_npe->rx_pkts[i * NPE_PKT_SIZE];
131                 IX_OSAL_MBUF_MLEN(m) = IX_OSAL_MBUF_PKT_LEN(m) = NPE_PKT_SIZE;
132
133                 if(ixEthAccPortRxFreeReplenish(p_npe->eth_id, m) != IX_SUCCESS) {
134                         printf("ixEthAccPortRxFreeReplenish failed for port %d\n", p_npe->eth_id);
135                         break;
136                 }
137         }
138 }
139
140 static void init_rx_mbufs(struct npe* p_npe)
141 {
142         p_npe->rxQHead = NULL;
143
144         p_npe->rx_pkts = npe_alloc(NPE_PKT_SIZE *
145                                    CONFIG_DEVS_ETH_INTEL_NPE_MAX_RX_DESCRIPTORS);
146         if (p_npe->rx_pkts == NULL) {
147                 printf("alloc of packets failed.\n");
148                 return;
149         }
150
151         p_npe->rx_mbufs = (IX_OSAL_MBUF *)
152                 npe_alloc(sizeof(IX_OSAL_MBUF) *
153                           CONFIG_DEVS_ETH_INTEL_NPE_MAX_RX_DESCRIPTORS);
154         if (p_npe->rx_mbufs == NULL) {
155                 printf("alloc of mbufs failed.\n");
156                 return;
157         }
158
159         reset_rx_mbufs(p_npe);
160 }
161
162 static void init_tx_mbufs(struct npe* p_npe)
163 {
164         p_npe->tx_pkts = npe_alloc(NPE_PKT_SIZE *
165                                    CONFIG_DEVS_ETH_INTEL_NPE_MAX_TX_DESCRIPTORS);
166         if (p_npe->tx_pkts == NULL) {
167                 printf("alloc of packets failed.\n");
168                 return;
169         }
170
171         p_npe->tx_mbufs = (IX_OSAL_MBUF *)
172                 npe_alloc(sizeof(IX_OSAL_MBUF) *
173                           CONFIG_DEVS_ETH_INTEL_NPE_MAX_TX_DESCRIPTORS);
174         if (p_npe->tx_mbufs == NULL) {
175                 printf("alloc of mbufs failed.\n");
176                 return;
177         }
178
179         reset_tx_mbufs(p_npe);
180 }
181
182 /* Convert IX_ETH_PORT_n to IX_NPEMH_NPEID_NPEx */
183 static int __eth_to_npe(int eth_id)
184 {
185         switch(eth_id) {
186         case IX_ETH_PORT_1:
187                 return IX_NPEMH_NPEID_NPEB;
188
189         case IX_ETH_PORT_2:
190                 return IX_NPEMH_NPEID_NPEC;
191
192         case IX_ETH_PORT_3:
193                 return IX_NPEMH_NPEID_NPEA;
194         }
195         return 0;
196 }
197
198 /* Poll the CSR machinery. */
199 static void npe_poll(int eth_id)
200 {
201         if (qDispatcherFunc != NULL) {
202                 ixNpeMhMessagesReceive(__eth_to_npe(eth_id));
203                 (*qDispatcherFunc)(IX_QMGR_QUELOW_GROUP);
204         }
205 }
206
207 /* ethAcc RX callback */
208 static void npe_rx_callback(u32 cbTag, IX_OSAL_MBUF *m, IxEthAccPortId portid)
209 {
210         struct npe* p_npe = (struct npe *)cbTag;
211
212         if (IX_OSAL_MBUF_MLEN(m) > 0) {
213                 mbuf_enqueue(&p_npe->rxQHead, m);
214
215                 if (p_npe->rx_write == ((p_npe->rx_read-1) & (PKTBUFSRX-1))) {
216                         debug("Rx overflow: rx_write=%d rx_read=%d\n",
217                               p_npe->rx_write, p_npe->rx_read);
218                 } else {
219                         debug("Received message #%d (len=%d)\n", p_npe->rx_write,
220                               IX_OSAL_MBUF_MLEN(m));
221                         memcpy((void *)NetRxPackets[p_npe->rx_write], IX_OSAL_MBUF_MDATA(m),
222                                IX_OSAL_MBUF_MLEN(m));
223                         p_npe->rx_len[p_npe->rx_write] = IX_OSAL_MBUF_MLEN(m);
224                         p_npe->rx_write++;
225                         if (p_npe->rx_write == PKTBUFSRX)
226                                 p_npe->rx_write = 0;
227
228 #ifdef CONFIG_PRINT_RX_FRAMES
229                         {
230                                 u8 *ptr = IX_OSAL_MBUF_MDATA(m);
231                                 int i;
232
233                                 for (i=0; i<60; i++) {
234                                         debug("%02x ", *ptr++);
235                                 }
236                                 debug("\n");
237                         }
238 #endif
239                 }
240
241                 m = mbuf_dequeue(&p_npe->rxQHead);
242         } else {
243                 debug("Received frame with length 0!!!\n");
244                 m = mbuf_dequeue(&p_npe->rxQHead);
245         }
246
247         /* Now return mbuf to NPE */
248         IX_OSAL_MBUF_MLEN(m) = IX_OSAL_MBUF_PKT_LEN(m) = NPE_PKT_SIZE;
249         IX_OSAL_MBUF_NEXT_BUFFER_IN_PKT_PTR(m) = NULL;
250         IX_OSAL_MBUF_FLAGS(m) = 0;
251
252         if(ixEthAccPortRxFreeReplenish(p_npe->eth_id, m) != IX_SUCCESS) {
253                 debug("npe_rx_callback: Error returning mbuf.\n");
254         }
255 }
256
257 /* ethAcc TX callback */
258 static void npe_tx_callback(u32 cbTag, IX_OSAL_MBUF *m)
259 {
260         struct npe* p_npe = (struct npe *)cbTag;
261
262         debug("%s\n", __FUNCTION__);
263
264         IX_OSAL_MBUF_MLEN(m) = IX_OSAL_MBUF_PKT_LEN(m) = NPE_PKT_SIZE;
265         IX_OSAL_MBUF_NEXT_BUFFER_IN_PKT_PTR(m) = NULL;
266         IX_OSAL_MBUF_FLAGS(m) = 0;
267
268         mbuf_enqueue(&p_npe->txQHead, m);
269 }
270
271
272 static int npe_set_mac_address(struct eth_device *dev)
273 {
274         struct npe *p_npe = (struct npe *)dev->priv;
275         IxEthAccMacAddr npeMac;
276
277         debug("%s\n", __FUNCTION__);
278
279         /* Set MAC address */
280         memcpy(npeMac.macAddress, dev->enetaddr, 6);
281
282         if (ixEthAccPortUnicastMacAddressSet(p_npe->eth_id, &npeMac) != IX_ETH_ACC_SUCCESS) {
283                 printf("Error setting unicast address! %02x:%02x:%02x:%02x:%02x:%02x\n",
284                        npeMac.macAddress[0], npeMac.macAddress[1],
285                        npeMac.macAddress[2], npeMac.macAddress[3],
286                        npeMac.macAddress[4], npeMac.macAddress[5]);
287                 return 0;
288         }
289
290         return 1;
291 }
292
293 /* Boot-time CSR library initialization. */
294 static int npe_csr_load(void)
295 {
296         int i;
297
298         if (ixQMgrInit() != IX_SUCCESS) {
299                 debug("Error initialising queue manager!\n");
300                 return 0;
301         }
302
303         ixQMgrDispatcherLoopGet(&qDispatcherFunc);
304
305         if(ixNpeMhInitialize(IX_NPEMH_NPEINTERRUPTS_YES) != IX_SUCCESS) {
306                 printf("Error initialising NPE Message handler!\n");
307                 return 0;
308         }
309
310         if (npe_used[IX_ETH_PORT_1] && npe_exists[IX_ETH_PORT_1] &&
311             ixNpeDlNpeInitAndStart(IX_NPEDL_NPEIMAGE_NPEB_ETH_LEARN_FILTER_SPAN_FIREWALL_VLAN_QOS)
312             != IX_SUCCESS) {
313                 printf("Error downloading firmware to NPE-B!\n");
314                 return 0;
315         }
316
317         if (npe_used[IX_ETH_PORT_2] && npe_exists[IX_ETH_PORT_2] &&
318             ixNpeDlNpeInitAndStart(IX_NPEDL_NPEIMAGE_NPEC_ETH_LEARN_FILTER_SPAN_FIREWALL_VLAN_QOS)
319             != IX_SUCCESS) {
320                 printf("Error downloading firmware to NPE-C!\n");
321                 return 0;
322         }
323
324         /* don't need this for U-Boot */
325         ixFeatureCtrlSwConfigurationWrite(IX_FEATURECTRL_ETH_LEARNING, false);
326
327         if (ixEthAccInit() != IX_ETH_ACC_SUCCESS) {
328                 printf("Error initialising Ethernet access driver!\n");
329                 return 0;
330         }
331
332         for (i = 0; i < IX_ETH_ACC_NUMBER_OF_PORTS; i++) {
333                 if (!npe_used[i] || !npe_exists[i])
334                         continue;
335                 if (ixEthAccPortInit(i) != IX_ETH_ACC_SUCCESS) {
336                         printf("Error initialising Ethernet port%d!\n", i);
337                 }
338                 if (ixEthAccTxSchedulingDisciplineSet(i, FIFO_NO_PRIORITY) != IX_ETH_ACC_SUCCESS) {
339                         printf("Error setting scheduling discipline for port %d.\n", i);
340                 }
341                 if (ixEthAccPortRxFrameAppendFCSDisable(i) != IX_ETH_ACC_SUCCESS) {
342                         printf("Error disabling RX FCS for port %d.\n", i);
343                 }
344                 if (ixEthAccPortTxFrameAppendFCSEnable(i) != IX_ETH_ACC_SUCCESS) {
345                         printf("Error enabling TX FCS for port %d.\n", i);
346                 }
347         }
348
349         return 1;
350 }
351
352 static int npe_init(struct eth_device *dev, bd_t * bis)
353 {
354         struct npe *p_npe = (struct npe *)dev->priv;
355         int i;
356         u16 reg_short;
357         int speed;
358         int duplex;
359
360         debug("%s: 1\n", __FUNCTION__);
361
362 #ifdef CONFIG_MII_NPE0_FIXEDLINK
363         if (0 == p_npe->eth_id) {
364                 speed = CONFIG_MII_NPE0_SPEED;
365                 duplex = CONFIG_MII_NPE0_FULLDUPLEX ? FULL : HALF;
366         } else
367 #endif
368 #ifdef CONFIG_MII_NPE1_FIXEDLINK
369         if (1 == p_npe->eth_id) {
370                 speed = CONFIG_MII_NPE1_SPEED;
371                 duplex = CONFIG_MII_NPE1_FULLDUPLEX ? FULL : HALF;
372         } else
373 #endif
374         {
375                 miiphy_read(dev->name, p_npe->phy_no, MII_BMSR, &reg_short);
376
377                 /*
378                  * Wait if PHY is capable of autonegotiation and
379                  * autonegotiation is not complete
380                  */
381                 if ((reg_short & BMSR_ANEGCAPABLE) &&
382                     !(reg_short & BMSR_ANEGCOMPLETE)) {
383                         puts("Waiting for PHY auto negotiation to complete");
384                         i = 0;
385                         while (!(reg_short & BMSR_ANEGCOMPLETE)) {
386                                 /*
387                                  * Timeout reached ?
388                                  */
389                                 if (i > PHY_AUTONEGOTIATE_TIMEOUT) {
390                                         puts(" TIMEOUT !\n");
391                                         break;
392                                 }
393
394                                 if ((i++ % 1000) == 0) {
395                                         putc('.');
396                                         miiphy_read(dev->name, p_npe->phy_no,
397                                                      MII_BMSR, &reg_short);
398                                 }
399                                 udelay(1000);   /* 1 ms */
400                         }
401                         puts(" done\n");
402                         /* another 500 ms (results in faster booting) */
403                         udelay(500000);
404                 }
405                 speed = miiphy_speed(dev->name, p_npe->phy_no);
406                 duplex = miiphy_duplex(dev->name, p_npe->phy_no);
407         }
408
409         if (p_npe->print_speed) {
410                 p_npe->print_speed = 0;
411                 printf ("ENET Speed is %d Mbps - %s duplex connection\n",
412                         (int) speed, (duplex == HALF) ? "HALF" : "FULL");
413         }
414
415         npe_alloc_end = npe_alloc_pool + sizeof(npe_alloc_pool);
416         npe_alloc_free = (u8 *)(((unsigned)npe_alloc_pool +
417                                  CONFIG_SYS_CACHELINE_SIZE - 1) & ~(CONFIG_SYS_CACHELINE_SIZE - 1));
418
419         /* initialize mbuf pool */
420         init_rx_mbufs(p_npe);
421         init_tx_mbufs(p_npe);
422
423         if (ixEthAccPortRxCallbackRegister(p_npe->eth_id, npe_rx_callback,
424                                            (u32)p_npe) != IX_ETH_ACC_SUCCESS) {
425                 printf("can't register RX callback!\n");
426                 return -1;
427         }
428
429         if (ixEthAccPortTxDoneCallbackRegister(p_npe->eth_id, npe_tx_callback,
430                                                (u32)p_npe) != IX_ETH_ACC_SUCCESS) {
431                 printf("can't register TX callback!\n");
432                 return -1;
433         }
434
435         npe_set_mac_address(dev);
436
437         if (ixEthAccPortEnable(p_npe->eth_id) != IX_ETH_ACC_SUCCESS) {
438                 printf("can't enable port!\n");
439                 return -1;
440         }
441
442         p_npe->active = 1;
443
444         return 0;
445 }
446
447 #if 0 /* test-only: probably have to deal with it when booting linux (for a clean state) */
448 /* Uninitialize CSR library. */
449 static void npe_csr_unload(void)
450 {
451         ixEthAccUnload();
452         ixEthDBUnload();
453         ixNpeMhUnload();
454         ixQMgrUnload();
455 }
456
457 /* callback which is used by ethAcc to recover RX buffers when stopping */
458 static void npe_rx_stop_callback(u32 cbTag, IX_OSAL_MBUF *m, IxEthAccPortId portid)
459 {
460         debug("%s\n", __FUNCTION__);
461 }
462
463 /* callback which is used by ethAcc to recover TX buffers when stopping */
464 static void npe_tx_stop_callback(u32 cbTag, IX_OSAL_MBUF *m)
465 {
466         debug("%s\n", __FUNCTION__);
467 }
468 #endif
469
470 static void npe_halt(struct eth_device *dev)
471 {
472         struct npe *p_npe = (struct npe *)dev->priv;
473         int i;
474
475         debug("%s\n", __FUNCTION__);
476
477         /* Delay to give time for recovery of mbufs */
478         for (i = 0; i < 100; i++) {
479                 npe_poll(p_npe->eth_id);
480                 udelay(100);
481         }
482
483 #if 0 /* test-only: probably have to deal with it when booting linux (for a clean state) */
484         if (ixEthAccPortRxCallbackRegister(p_npe->eth_id, npe_rx_stop_callback,
485                                            (u32)p_npe) != IX_ETH_ACC_SUCCESS) {
486                 debug("Error registering rx callback!\n");
487         }
488
489         if (ixEthAccPortTxDoneCallbackRegister(p_npe->eth_id, npe_tx_stop_callback,
490                                                (u32)p_npe) != IX_ETH_ACC_SUCCESS) {
491                 debug("Error registering tx callback!\n");
492         }
493
494         if (ixEthAccPortDisable(p_npe->eth_id) != IX_ETH_ACC_SUCCESS) {
495                 debug("npe_stop: Error disabling NPEB!\n");
496         }
497
498         /* Delay to give time for recovery of mbufs */
499         for (i = 0; i < 100; i++) {
500                 npe_poll(p_npe->eth_id);
501                 udelay(10000);
502         }
503
504         /*
505          * For U-Boot only, we are probably launching Linux or other OS that
506          * needs a clean slate for its NPE library.
507          */
508 #if 0 /* test-only */
509         for (i = 0; i < IX_ETH_ACC_NUMBER_OF_PORTS; i++) {
510                 if (npe_used[i] && npe_exists[i])
511                         if (ixNpeDlNpeStopAndReset(__eth_to_npe(i)) != IX_SUCCESS)
512                                 printf("Failed to stop and reset NPE B.\n");
513         }
514 #endif
515
516 #endif
517         p_npe->active = 0;
518 }
519
520
521 static int npe_send(struct eth_device *dev, void *packet, int len)
522 {
523         struct npe *p_npe = (struct npe *)dev->priv;
524         u8 *dest;
525         int err;
526         IX_OSAL_MBUF *m;
527
528         debug("%s\n", __FUNCTION__);
529         m = mbuf_dequeue(&p_npe->txQHead);
530         dest = IX_OSAL_MBUF_MDATA(m);
531         IX_OSAL_MBUF_PKT_LEN(m) = IX_OSAL_MBUF_MLEN(m) = len;
532         IX_OSAL_MBUF_NEXT_PKT_IN_CHAIN_PTR(m) = NULL;
533
534         memcpy(dest, (char *)packet, len);
535
536         if ((err = ixEthAccPortTxFrameSubmit(p_npe->eth_id, m, IX_ETH_ACC_TX_DEFAULT_PRIORITY))
537             != IX_ETH_ACC_SUCCESS) {
538                 printf("npe_send: Can't submit frame. err[%d]\n", err);
539                 mbuf_enqueue(&p_npe->txQHead, m);
540                 return 0;
541         }
542
543 #ifdef DEBUG_PRINT_TX_FRAMES
544         {
545                 u8 *ptr = IX_OSAL_MBUF_MDATA(m);
546                 int i;
547
548                 for (i=0; i<IX_OSAL_MBUF_MLEN(m); i++) {
549                         printf("%02x ", *ptr++);
550                 }
551                 printf(" (tx-len=%d)\n", IX_OSAL_MBUF_MLEN(m));
552         }
553 #endif
554
555         npe_poll(p_npe->eth_id);
556
557         return len;
558 }
559
560 static int npe_rx(struct eth_device *dev)
561 {
562         struct npe *p_npe = (struct npe *)dev->priv;
563
564         debug("%s\n", __FUNCTION__);
565         npe_poll(p_npe->eth_id);
566
567         debug("%s: rx_write=%d rx_read=%d\n", __FUNCTION__, p_npe->rx_write, p_npe->rx_read);
568         while (p_npe->rx_write != p_npe->rx_read) {
569                 debug("Reading message #%d\n", p_npe->rx_read);
570                 NetReceive(NetRxPackets[p_npe->rx_read], p_npe->rx_len[p_npe->rx_read]);
571                 p_npe->rx_read++;
572                 if (p_npe->rx_read == PKTBUFSRX)
573                         p_npe->rx_read = 0;
574         }
575
576         return 0;
577 }
578
579 int npe_initialize(bd_t * bis)
580 {
581         static int virgin = 0;
582         struct eth_device *dev;
583         int eth_num = 0;
584         struct npe *p_npe = NULL;
585         uchar enetaddr[6];
586
587         for (eth_num = 0; eth_num < CONFIG_SYS_NPE_NUMS; eth_num++) {
588
589                 /* See if we can actually bring up the interface, otherwise, skip it */
590 #ifdef CONFIG_HAS_ETH1
591                 if (eth_num == 1) {
592                         if (!eth_getenv_enetaddr("eth1addr", enetaddr))
593                                 continue;
594                 } else
595 #endif
596                         if (!eth_getenv_enetaddr("ethaddr", enetaddr))
597                                 continue;
598
599                 /* Allocate device structure */
600                 dev = (struct eth_device *)malloc(sizeof(*dev));
601                 if (dev == NULL) {
602                         printf ("%s: Cannot allocate eth_device %d\n", __FUNCTION__, eth_num);
603                         return -1;
604                 }
605                 memset(dev, 0, sizeof(*dev));
606
607                 /* Allocate our private use data */
608                 p_npe = (struct npe *)malloc(sizeof(struct npe));
609                 if (p_npe == NULL) {
610                         printf("%s: Cannot allocate private hw data for eth_device %d",
611                                __FUNCTION__, eth_num);
612                         free(dev);
613                         return -1;
614                 }
615                 memset(p_npe, 0, sizeof(struct npe));
616
617                 p_npe->eth_id = eth_num;
618                 memcpy(dev->enetaddr, enetaddr, 6);
619 #ifdef CONFIG_HAS_ETH1
620                 if (eth_num == 1)
621                         p_npe->phy_no = CONFIG_PHY1_ADDR;
622                 else
623 #endif
624                         p_npe->phy_no = CONFIG_PHY_ADDR;
625
626                 sprintf(dev->name, "NPE%d", eth_num);
627                 dev->priv = (void *)p_npe;
628                 dev->init = npe_init;
629                 dev->halt = npe_halt;
630                 dev->send = npe_send;
631                 dev->recv = npe_rx;
632
633                 p_npe->print_speed = 1;
634
635                 if (0 == virgin) {
636                         virgin = 1;
637
638                         if (ixFeatureCtrlDeviceRead() == IX_FEATURE_CTRL_DEVICE_TYPE_IXP42X) {
639                                 switch (ixFeatureCtrlProductIdRead() & IX_FEATURE_CTRL_SILICON_STEPPING_MASK) {
640                                 case IX_FEATURE_CTRL_SILICON_TYPE_B0:
641                                 default: /* newer than B0 */
642                                         /*
643                                          * If it is B0 or newer Silicon, we
644                                          * only enable port when its
645                                          * corresponding Eth Coprocessor is
646                                          * available.
647                                          */
648                                         if (ixFeatureCtrlComponentCheck(IX_FEATURECTRL_ETH0) ==
649                                             IX_FEATURE_CTRL_COMPONENT_ENABLED)
650                                                 npe_exists[IX_ETH_PORT_1] = true;
651
652                                         if (ixFeatureCtrlComponentCheck(IX_FEATURECTRL_ETH1) ==
653                                             IX_FEATURE_CTRL_COMPONENT_ENABLED)
654                                                 npe_exists[IX_ETH_PORT_2] = true;
655                                         break;
656                                 case IX_FEATURE_CTRL_SILICON_TYPE_A0:
657                                         /*
658                                          * If it is A0 Silicon, we enable both as both Eth Coprocessors
659                                          * are available.
660                                          */
661                                         npe_exists[IX_ETH_PORT_1] = true;
662                                         npe_exists[IX_ETH_PORT_2] = true;
663                                         break;
664                                 }
665                         } else if (ixFeatureCtrlDeviceRead() == IX_FEATURE_CTRL_DEVICE_TYPE_IXP46X) {
666                                 if (ixFeatureCtrlComponentCheck(IX_FEATURECTRL_ETH0) ==
667                                     IX_FEATURE_CTRL_COMPONENT_ENABLED)
668                                         npe_exists[IX_ETH_PORT_1] = true;
669
670                                 if (ixFeatureCtrlComponentCheck(IX_FEATURECTRL_ETH1) ==
671                                     IX_FEATURE_CTRL_COMPONENT_ENABLED)
672                                         npe_exists[IX_ETH_PORT_2] = true;
673                         }
674
675                         npe_used[IX_ETH_PORT_1] = 1;
676                         npe_used[IX_ETH_PORT_2] = 1;
677
678                         npe_alloc_end = npe_alloc_pool + sizeof(npe_alloc_pool);
679                         npe_alloc_free = (u8 *)(((unsigned)npe_alloc_pool +
680                                                  CONFIG_SYS_CACHELINE_SIZE - 1)
681                                                 & ~(CONFIG_SYS_CACHELINE_SIZE - 1));
682
683                         if (!npe_csr_load())
684                                 return 0;
685                 }
686
687                 eth_register(dev);
688
689 #if defined(CONFIG_MII) || defined(CONFIG_CMD_MII)
690                 miiphy_register(dev->name, npe_miiphy_read, npe_miiphy_write);
691 #endif
692
693         }                       /* end for each supported device */
694
695         return 1;
696 }