2 * (C) Copyright 2005-2006
3 * Stefan Roese, DENX Software Engineering, sr@denx.de.
5 * See file CREDITS for list of people who contributed to this
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.
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.
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,
25 #define DEBUG /* define for debug output */
33 #include <asm/processor.h>
34 #include <asm/arch-ixp/ixp425.h>
43 #include <IxFeatureCtrl.h>
47 static IxQMgrDispatcherFuncPtr qDispatcherFunc = NULL;
48 static int npe_exists[NPE_NUM_PORTS];
49 static int npe_used[NPE_NUM_PORTS];
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;
56 static void *npe_alloc(int size)
61 size = (size + (CONFIG_SYS_CACHELINE_SIZE-1)) & ~(CONFIG_SYS_CACHELINE_SIZE-1);
64 if ((npe_alloc_free + size) < npe_alloc_end) {
66 npe_alloc_free += size;
68 printf("npe_alloc: failed (count=%d, size=%d)!\n", count, size);
73 /* Not interrupt safe! */
74 static void mbuf_enqueue(IX_OSAL_MBUF **q, IX_OSAL_MBUF *new)
78 IX_OSAL_MBUF_NEXT_PKT_IN_CHAIN_PTR(new) = NULL;
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;
88 /* Not interrupt safe! */
89 static IX_OSAL_MBUF *mbuf_dequeue(IX_OSAL_MBUF **q)
93 *q = IX_OSAL_MBUF_NEXT_PKT_IN_CHAIN_PTR(m);
97 static void reset_tx_mbufs(struct npe* p_npe)
102 p_npe->txQHead = NULL;
104 for (i = 0; i < CONFIG_DEVS_ETH_INTEL_NPE_MAX_TX_DESCRIPTORS; i++) {
105 m = &p_npe->tx_mbufs[i];
107 memset(m, 0, sizeof(*m));
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);
115 static void reset_rx_mbufs(struct npe* p_npe)
120 p_npe->rxQHead = NULL;
122 HAL_DCACHE_INVALIDATE(p_npe->rx_pkts, NPE_PKT_SIZE *
123 CONFIG_DEVS_ETH_INTEL_NPE_MAX_RX_DESCRIPTORS);
125 for (i = 0; i < CONFIG_DEVS_ETH_INTEL_NPE_MAX_RX_DESCRIPTORS; i++) {
126 m = &p_npe->rx_mbufs[i];
128 memset(m, 0, sizeof(*m));
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;
133 if(ixEthAccPortRxFreeReplenish(p_npe->eth_id, m) != IX_SUCCESS) {
134 printf("ixEthAccPortRxFreeReplenish failed for port %d\n", p_npe->eth_id);
140 static void init_rx_mbufs(struct npe* p_npe)
142 p_npe->rxQHead = NULL;
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");
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");
159 reset_rx_mbufs(p_npe);
162 static void init_tx_mbufs(struct npe* p_npe)
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");
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");
179 reset_tx_mbufs(p_npe);
182 /* Convert IX_ETH_PORT_n to IX_NPEMH_NPEID_NPEx */
183 static int __eth_to_npe(int eth_id)
187 return IX_NPEMH_NPEID_NPEB;
190 return IX_NPEMH_NPEID_NPEC;
193 return IX_NPEMH_NPEID_NPEA;
198 /* Poll the CSR machinery. */
199 static void npe_poll(int eth_id)
201 if (qDispatcherFunc != NULL) {
202 ixNpeMhMessagesReceive(__eth_to_npe(eth_id));
203 (*qDispatcherFunc)(IX_QMGR_QUELOW_GROUP);
207 /* ethAcc RX callback */
208 static void npe_rx_callback(u32 cbTag, IX_OSAL_MBUF *m, IxEthAccPortId portid)
210 struct npe* p_npe = (struct npe *)cbTag;
212 if (IX_OSAL_MBUF_MLEN(m) > 0) {
213 mbuf_enqueue(&p_npe->rxQHead, m);
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);
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);
225 if (p_npe->rx_write == PKTBUFSRX)
228 #ifdef CONFIG_PRINT_RX_FRAMES
230 u8 *ptr = IX_OSAL_MBUF_MDATA(m);
233 for (i=0; i<60; i++) {
234 debug("%02x ", *ptr++);
241 m = mbuf_dequeue(&p_npe->rxQHead);
243 debug("Received frame with length 0!!!\n");
244 m = mbuf_dequeue(&p_npe->rxQHead);
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;
252 if(ixEthAccPortRxFreeReplenish(p_npe->eth_id, m) != IX_SUCCESS) {
253 debug("npe_rx_callback: Error returning mbuf.\n");
257 /* ethAcc TX callback */
258 static void npe_tx_callback(u32 cbTag, IX_OSAL_MBUF *m)
260 struct npe* p_npe = (struct npe *)cbTag;
262 debug("%s\n", __FUNCTION__);
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;
268 mbuf_enqueue(&p_npe->txQHead, m);
272 static int npe_set_mac_address(struct eth_device *dev)
274 struct npe *p_npe = (struct npe *)dev->priv;
275 IxEthAccMacAddr npeMac;
277 debug("%s\n", __FUNCTION__);
279 /* Set MAC address */
280 memcpy(npeMac.macAddress, dev->enetaddr, 6);
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]);
293 /* Boot-time CSR library initialization. */
294 static int npe_csr_load(void)
298 if (ixQMgrInit() != IX_SUCCESS) {
299 debug("Error initialising queue manager!\n");
303 ixQMgrDispatcherLoopGet(&qDispatcherFunc);
305 if(ixNpeMhInitialize(IX_NPEMH_NPEINTERRUPTS_YES) != IX_SUCCESS) {
306 printf("Error initialising NPE Message handler!\n");
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)
313 printf("Error downloading firmware to NPE-B!\n");
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)
320 printf("Error downloading firmware to NPE-C!\n");
324 /* don't need this for U-Boot */
325 ixFeatureCtrlSwConfigurationWrite(IX_FEATURECTRL_ETH_LEARNING, FALSE);
327 if (ixEthAccInit() != IX_ETH_ACC_SUCCESS) {
328 printf("Error initialising Ethernet access driver!\n");
332 for (i = 0; i < IX_ETH_ACC_NUMBER_OF_PORTS; i++) {
333 if (!npe_used[i] || !npe_exists[i])
335 if (ixEthAccPortInit(i) != IX_ETH_ACC_SUCCESS) {
336 printf("Error initialising Ethernet port%d!\n", i);
338 if (ixEthAccTxSchedulingDisciplineSet(i, FIFO_NO_PRIORITY) != IX_ETH_ACC_SUCCESS) {
339 printf("Error setting scheduling discipline for port %d.\n", i);
341 if (ixEthAccPortRxFrameAppendFCSDisable(i) != IX_ETH_ACC_SUCCESS) {
342 printf("Error disabling RX FCS for port %d.\n", i);
344 if (ixEthAccPortTxFrameAppendFCSEnable(i) != IX_ETH_ACC_SUCCESS) {
345 printf("Error enabling TX FCS for port %d.\n", i);
352 static int npe_init(struct eth_device *dev, bd_t * bis)
354 struct npe *p_npe = (struct npe *)dev->priv;
360 debug("%s: 1\n", __FUNCTION__);
362 miiphy_read (dev->name, p_npe->phy_no, PHY_BMSR, ®_short);
365 * Wait if PHY is capable of autonegotiation and autonegotiation is not complete
367 if ((reg_short & PHY_BMSR_AUTN_ABLE) && !(reg_short & PHY_BMSR_AUTN_COMP)) {
368 puts ("Waiting for PHY auto negotiation to complete");
370 while (!(reg_short & PHY_BMSR_AUTN_COMP)) {
374 if (i > PHY_AUTONEGOTIATE_TIMEOUT) {
375 puts (" TIMEOUT !\n");
379 if ((i++ % 1000) == 0) {
381 miiphy_read (dev->name, p_npe->phy_no, PHY_BMSR, ®_short);
383 udelay (1000); /* 1 ms */
386 udelay (500000); /* another 500 ms (results in faster booting) */
389 speed = miiphy_speed (dev->name, p_npe->phy_no);
390 duplex = miiphy_duplex (dev->name, p_npe->phy_no);
392 if (p_npe->print_speed) {
393 p_npe->print_speed = 0;
394 printf ("ENET Speed is %d Mbps - %s duplex connection\n",
395 (int) speed, (duplex == HALF) ? "HALF" : "FULL");
398 npe_alloc_end = npe_alloc_pool + sizeof(npe_alloc_pool);
399 npe_alloc_free = (u8 *)(((unsigned)npe_alloc_pool +
400 CONFIG_SYS_CACHELINE_SIZE - 1) & ~(CONFIG_SYS_CACHELINE_SIZE - 1));
402 /* initialize mbuf pool */
403 init_rx_mbufs(p_npe);
404 init_tx_mbufs(p_npe);
406 if (ixEthAccPortRxCallbackRegister(p_npe->eth_id, npe_rx_callback,
407 (u32)p_npe) != IX_ETH_ACC_SUCCESS) {
408 printf("can't register RX callback!\n");
412 if (ixEthAccPortTxDoneCallbackRegister(p_npe->eth_id, npe_tx_callback,
413 (u32)p_npe) != IX_ETH_ACC_SUCCESS) {
414 printf("can't register TX callback!\n");
418 npe_set_mac_address(dev);
420 if (ixEthAccPortEnable(p_npe->eth_id) != IX_ETH_ACC_SUCCESS) {
421 printf("can't enable port!\n");
430 #if 0 /* test-only: probably have to deal with it when booting linux (for a clean state) */
431 /* Uninitialize CSR library. */
432 static void npe_csr_unload(void)
440 /* callback which is used by ethAcc to recover RX buffers when stopping */
441 static void npe_rx_stop_callback(u32 cbTag, IX_OSAL_MBUF *m, IxEthAccPortId portid)
443 debug("%s\n", __FUNCTION__);
446 /* callback which is used by ethAcc to recover TX buffers when stopping */
447 static void npe_tx_stop_callback(u32 cbTag, IX_OSAL_MBUF *m)
449 debug("%s\n", __FUNCTION__);
453 static void npe_halt(struct eth_device *dev)
455 struct npe *p_npe = (struct npe *)dev->priv;
458 debug("%s\n", __FUNCTION__);
460 /* Delay to give time for recovery of mbufs */
461 for (i = 0; i < 100; i++) {
462 npe_poll(p_npe->eth_id);
466 #if 0 /* test-only: probably have to deal with it when booting linux (for a clean state) */
467 if (ixEthAccPortRxCallbackRegister(p_npe->eth_id, npe_rx_stop_callback,
468 (u32)p_npe) != IX_ETH_ACC_SUCCESS) {
469 debug("Error registering rx callback!\n");
472 if (ixEthAccPortTxDoneCallbackRegister(p_npe->eth_id, npe_tx_stop_callback,
473 (u32)p_npe) != IX_ETH_ACC_SUCCESS) {
474 debug("Error registering tx callback!\n");
477 if (ixEthAccPortDisable(p_npe->eth_id) != IX_ETH_ACC_SUCCESS) {
478 debug("npe_stop: Error disabling NPEB!\n");
481 /* Delay to give time for recovery of mbufs */
482 for (i = 0; i < 100; i++) {
483 npe_poll(p_npe->eth_id);
488 * For U-Boot only, we are probably launching Linux or other OS that
489 * needs a clean slate for its NPE library.
491 #if 0 /* test-only */
492 for (i = 0; i < IX_ETH_ACC_NUMBER_OF_PORTS; i++) {
493 if (npe_used[i] && npe_exists[i])
494 if (ixNpeDlNpeStopAndReset(__eth_to_npe(i)) != IX_SUCCESS)
495 printf("Failed to stop and reset NPE B.\n");
504 static int npe_send(struct eth_device *dev, volatile void *packet, int len)
506 struct npe *p_npe = (struct npe *)dev->priv;
511 debug("%s\n", __FUNCTION__);
512 m = mbuf_dequeue(&p_npe->txQHead);
513 dest = IX_OSAL_MBUF_MDATA(m);
514 IX_OSAL_MBUF_PKT_LEN(m) = IX_OSAL_MBUF_MLEN(m) = len;
515 IX_OSAL_MBUF_NEXT_PKT_IN_CHAIN_PTR(m) = NULL;
517 memcpy(dest, (char *)packet, len);
519 if ((err = ixEthAccPortTxFrameSubmit(p_npe->eth_id, m, IX_ETH_ACC_TX_DEFAULT_PRIORITY))
520 != IX_ETH_ACC_SUCCESS) {
521 printf("npe_send: Can't submit frame. err[%d]\n", err);
522 mbuf_enqueue(&p_npe->txQHead, m);
526 #ifdef DEBUG_PRINT_TX_FRAMES
528 u8 *ptr = IX_OSAL_MBUF_MDATA(m);
531 for (i=0; i<IX_OSAL_MBUF_MLEN(m); i++) {
532 printf("%02x ", *ptr++);
534 printf(" (tx-len=%d)\n", IX_OSAL_MBUF_MLEN(m));
538 npe_poll(p_npe->eth_id);
543 static int npe_rx(struct eth_device *dev)
545 struct npe *p_npe = (struct npe *)dev->priv;
547 debug("%s\n", __FUNCTION__);
548 npe_poll(p_npe->eth_id);
550 debug("%s: rx_write=%d rx_read=%d\n", __FUNCTION__, p_npe->rx_write, p_npe->rx_read);
551 while (p_npe->rx_write != p_npe->rx_read) {
552 debug("Reading message #%d\n", p_npe->rx_read);
553 NetReceive(NetRxPackets[p_npe->rx_read], p_npe->rx_len[p_npe->rx_read]);
555 if (p_npe->rx_read == PKTBUFSRX)
562 int npe_initialize(bd_t * bis)
564 static int virgin = 0;
565 struct eth_device *dev;
567 struct npe *p_npe = NULL;
569 for (eth_num = 0; eth_num < CONFIG_SYS_NPE_NUMS; eth_num++) {
571 /* See if we can actually bring up the interface, otherwise, skip it */
573 default: /* fall through */
575 if (memcmp (bis->bi_enetaddr, "\0\0\0\0\0\0", 6) == 0) {
579 #ifdef CONFIG_HAS_ETH1
581 if (memcmp (bis->bi_enet1addr, "\0\0\0\0\0\0", 6) == 0) {
588 /* Allocate device structure */
589 dev = (struct eth_device *)malloc(sizeof(*dev));
591 printf ("%s: Cannot allocate eth_device %d\n", __FUNCTION__, eth_num);
594 memset(dev, 0, sizeof(*dev));
596 /* Allocate our private use data */
597 p_npe = (struct npe *)malloc(sizeof(struct npe));
599 printf("%s: Cannot allocate private hw data for eth_device %d",
600 __FUNCTION__, eth_num);
604 memset(p_npe, 0, sizeof(struct npe));
607 default: /* fall through */
609 memcpy(dev->enetaddr, bis->bi_enetaddr, 6);
611 p_npe->phy_no = CONFIG_PHY_ADDR;
614 #ifdef CONFIG_HAS_ETH1
616 memcpy(dev->enetaddr, bis->bi_enet1addr, 6);
618 p_npe->phy_no = CONFIG_PHY1_ADDR;
623 sprintf(dev->name, "NPE%d", eth_num);
624 dev->priv = (void *)p_npe;
625 dev->init = npe_init;
626 dev->halt = npe_halt;
627 dev->send = npe_send;
630 p_npe->print_speed = 1;
635 if (ixFeatureCtrlDeviceRead() == IX_FEATURE_CTRL_DEVICE_TYPE_IXP42X) {
636 switch (ixFeatureCtrlProductIdRead() & IX_FEATURE_CTRL_SILICON_STEPPING_MASK) {
637 case IX_FEATURE_CTRL_SILICON_TYPE_B0:
639 * If it is B0 Silicon, we only enable port when its corresponding
640 * Eth Coprocessor is available.
642 if (ixFeatureCtrlComponentCheck(IX_FEATURECTRL_ETH0) ==
643 IX_FEATURE_CTRL_COMPONENT_ENABLED)
644 npe_exists[IX_ETH_PORT_1] = TRUE;
646 if (ixFeatureCtrlComponentCheck(IX_FEATURECTRL_ETH1) ==
647 IX_FEATURE_CTRL_COMPONENT_ENABLED)
648 npe_exists[IX_ETH_PORT_2] = TRUE;
650 case IX_FEATURE_CTRL_SILICON_TYPE_A0:
652 * If it is A0 Silicon, we enable both as both Eth Coprocessors
655 npe_exists[IX_ETH_PORT_1] = TRUE;
656 npe_exists[IX_ETH_PORT_2] = TRUE;
659 } else if (ixFeatureCtrlDeviceRead() == IX_FEATURE_CTRL_DEVICE_TYPE_IXP46X) {
660 if (ixFeatureCtrlComponentCheck(IX_FEATURECTRL_ETH0) ==
661 IX_FEATURE_CTRL_COMPONENT_ENABLED)
662 npe_exists[IX_ETH_PORT_1] = TRUE;
664 if (ixFeatureCtrlComponentCheck(IX_FEATURECTRL_ETH1) ==
665 IX_FEATURE_CTRL_COMPONENT_ENABLED)
666 npe_exists[IX_ETH_PORT_2] = TRUE;
669 npe_used[IX_ETH_PORT_1] = 1;
670 npe_used[IX_ETH_PORT_2] = 1;
672 npe_alloc_end = npe_alloc_pool + sizeof(npe_alloc_pool);
673 npe_alloc_free = (u8 *)(((unsigned)npe_alloc_pool +
674 CONFIG_SYS_CACHELINE_SIZE - 1)
675 & ~(CONFIG_SYS_CACHELINE_SIZE - 1));
683 #if defined(CONFIG_MII) || defined(CONFIG_CMD_MII)
684 miiphy_register(dev->name, npe_miiphy_read, npe_miiphy_write);
687 } /* end for each supported device */