blob: 1fe3a95eaf2944c76f1a5a4330f494c2241f0401 [file] [log] [blame]
Wolfgang Denkba94a1b2006-05-30 15:56:48 +02001/*
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
Wolfgang Denkba94a1b2006-05-30 15:56:48 +020047static IxQMgrDispatcherFuncPtr qDispatcherFunc = NULL;
48static int npe_exists[NPE_NUM_PORTS];
49static int npe_used[NPE_NUM_PORTS];
50
51/* A little extra so we can align to cacheline. */
Jean-Christophe PLAGNIOL-VILLARD6d0f6bc2008-10-16 15:01:15 +020052static u8 npe_alloc_pool[NPE_MEM_POOL_SIZE + CONFIG_SYS_CACHELINE_SIZE - 1];
Wolfgang Denkba94a1b2006-05-30 15:56:48 +020053static u8 *npe_alloc_end;
54static u8 *npe_alloc_free;
55
56static void *npe_alloc(int size)
57{
58 static int count = 0;
59 void *p = NULL;
60
Jean-Christophe PLAGNIOL-VILLARD6d0f6bc2008-10-16 15:01:15 +020061 size = (size + (CONFIG_SYS_CACHELINE_SIZE-1)) & ~(CONFIG_SYS_CACHELINE_SIZE-1);
Wolfgang Denkba94a1b2006-05-30 15:56:48 +020062 count++;
63
64 if ((npe_alloc_free + size) < npe_alloc_end) {
65 p = npe_alloc_free;
66 npe_alloc_free += size;
67 } else {
Wolfgang Denk25dbe982008-07-13 23:07:35 +020068 printf("npe_alloc: failed (count=%d, size=%d)!\n", count, size);
Wolfgang Denkba94a1b2006-05-30 15:56:48 +020069 }
70 return p;
71}
72
73/* Not interrupt safe! */
74static 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! */
89static 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
97static 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
115static 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
140static 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
162static 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 */
183static 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. */
199static 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 */
208static 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 */
258static 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
272static 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. */
294static 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
352static 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
Michael Schwingend697d792011-05-23 00:00:08 +0200362#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);
Wolfgang Denkba94a1b2006-05-30 15:56:48 +0200376
Michael Schwingend697d792011-05-23 00:00:08 +0200377 /*
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 }
Wolfgang Denkba94a1b2006-05-30 15:56:48 +0200393
Michael Schwingend697d792011-05-23 00:00:08 +0200394 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 */
Wolfgang Denkba94a1b2006-05-30 15:56:48 +0200400 }
Michael Schwingend697d792011-05-23 00:00:08 +0200401 puts(" done\n");
402 /* another 500 ms (results in faster booting) */
403 udelay(500000);
Wolfgang Denkba94a1b2006-05-30 15:56:48 +0200404 }
Michael Schwingend697d792011-05-23 00:00:08 +0200405 speed = miiphy_speed(dev->name, p_npe->phy_no);
406 duplex = miiphy_duplex(dev->name, p_npe->phy_no);
Wolfgang Denkba94a1b2006-05-30 15:56:48 +0200407 }
408
Wolfgang Denkba94a1b2006-05-30 15:56:48 +0200409 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 +
Jean-Christophe PLAGNIOL-VILLARD6d0f6bc2008-10-16 15:01:15 +0200417 CONFIG_SYS_CACHELINE_SIZE - 1) & ~(CONFIG_SYS_CACHELINE_SIZE - 1));
Wolfgang Denkba94a1b2006-05-30 15:56:48 +0200418
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");
Ben Warren422b1a02008-01-09 18:15:53 -0500426 return -1;
Wolfgang Denkba94a1b2006-05-30 15:56:48 +0200427 }
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");
Ben Warren422b1a02008-01-09 18:15:53 -0500432 return -1;
Wolfgang Denkba94a1b2006-05-30 15:56:48 +0200433 }
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");
Ben Warren422b1a02008-01-09 18:15:53 -0500439 return -1;
Wolfgang Denkba94a1b2006-05-30 15:56:48 +0200440 }
441
442 p_npe->active = 1;
443
Ben Warren422b1a02008-01-09 18:15:53 -0500444 return 0;
Wolfgang Denkba94a1b2006-05-30 15:56:48 +0200445}
446
447#if 0 /* test-only: probably have to deal with it when booting linux (for a clean state) */
448/* Uninitialize CSR library. */
449static 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 */
458static 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 */
464static void npe_tx_stop_callback(u32 cbTag, IX_OSAL_MBUF *m)
465{
466 debug("%s\n", __FUNCTION__);
467}
468#endif
469
470static 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
Anatolij Gustschin287e3ad2012-05-20 12:22:58 +0000521static int npe_send(struct eth_device *dev, void *packet, int len)
Wolfgang Denkba94a1b2006-05-30 15:56:48 +0200522{
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
560static 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
579int 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;
Mike Frysinger740e8ba2009-02-11 19:19:54 -0500585 uchar enetaddr[6];
Wolfgang Denkba94a1b2006-05-30 15:56:48 +0200586
Jean-Christophe PLAGNIOL-VILLARD6d0f6bc2008-10-16 15:01:15 +0200587 for (eth_num = 0; eth_num < CONFIG_SYS_NPE_NUMS; eth_num++) {
Wolfgang Denkba94a1b2006-05-30 15:56:48 +0200588
589 /* See if we can actually bring up the interface, otherwise, skip it */
Wolfgang Denkba94a1b2006-05-30 15:56:48 +0200590#ifdef CONFIG_HAS_ETH1
Mike Frysinger740e8ba2009-02-11 19:19:54 -0500591 if (eth_num == 1) {
592 if (!eth_getenv_enetaddr("eth1addr", enetaddr))
Wolfgang Denkba94a1b2006-05-30 15:56:48 +0200593 continue;
Mike Frysinger740e8ba2009-02-11 19:19:54 -0500594 } else
Wolfgang Denkba94a1b2006-05-30 15:56:48 +0200595#endif
Mike Frysinger740e8ba2009-02-11 19:19:54 -0500596 if (!eth_getenv_enetaddr("ethaddr", enetaddr))
597 continue;
Wolfgang Denkba94a1b2006-05-30 15:56:48 +0200598
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
Mike Frysinger740e8ba2009-02-11 19:19:54 -0500617 p_npe->eth_id = eth_num;
618 memcpy(dev->enetaddr, enetaddr, 6);
Wolfgang Denkba94a1b2006-05-30 15:56:48 +0200619#ifdef CONFIG_HAS_ETH1
Mike Frysinger740e8ba2009-02-11 19:19:54 -0500620 if (eth_num == 1)
Wolfgang Denkba94a1b2006-05-30 15:56:48 +0200621 p_npe->phy_no = CONFIG_PHY1_ADDR;
Mike Frysinger740e8ba2009-02-11 19:19:54 -0500622 else
Wolfgang Denkba94a1b2006-05-30 15:56:48 +0200623#endif
Mike Frysinger740e8ba2009-02-11 19:19:54 -0500624 p_npe->phy_no = CONFIG_PHY_ADDR;
Wolfgang Denkba94a1b2006-05-30 15:56:48 +0200625
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:
Michael Schwingen20f17282011-05-22 23:59:58 +0200641 default: /* newer than B0 */
Wolfgang Denkba94a1b2006-05-30 15:56:48 +0200642 /*
Michael Schwingen20f17282011-05-22 23:59:58 +0200643 * If it is B0 or newer Silicon, we
644 * only enable port when its
645 * corresponding Eth Coprocessor is
646 * available.
Wolfgang Denkba94a1b2006-05-30 15:56:48 +0200647 */
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 +
Jean-Christophe PLAGNIOL-VILLARD6d0f6bc2008-10-16 15:01:15 +0200680 CONFIG_SYS_CACHELINE_SIZE - 1)
681 & ~(CONFIG_SYS_CACHELINE_SIZE - 1));
Wolfgang Denkba94a1b2006-05-30 15:56:48 +0200682
683 if (!npe_csr_load())
684 return 0;
685 }
686
687 eth_register(dev);
688
Jon Loeliger3a1ed1e2007-07-09 18:57:22 -0500689#if defined(CONFIG_MII) || defined(CONFIG_CMD_MII)
Wolfgang Denkba94a1b2006-05-30 15:56:48 +0200690 miiphy_register(dev->name, npe_miiphy_read, npe_miiphy_write);
691#endif
692
693 } /* end for each supported device */
694
695 return 1;
696}