|  | /* | 
|  | * (C) Copyright 2005-2006 | 
|  | * Stefan Roese, DENX Software Engineering, sr@denx.de. | 
|  | * | 
|  | * See file CREDITS for list of people who contributed to this | 
|  | * project. | 
|  | * | 
|  | * This program is free software; you can redistribute it and/or | 
|  | * modify it under the terms of the GNU General Public License as | 
|  | * published by the Free Software Foundation; either version 2 of | 
|  | * the License, or (at your option) any later version. | 
|  | * | 
|  | * This program is distributed in the hope that it will be useful, | 
|  | * but WITHOUT ANY WARRANTY; without even the implied warranty of | 
|  | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | 
|  | * GNU General Public License for more details. | 
|  | * | 
|  | * You should have received a copy of the GNU General Public License | 
|  | * along with this program; if not, write to the Free Software | 
|  | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, | 
|  | * MA 02111-1307 USA | 
|  | */ | 
|  |  | 
|  | #if 0 | 
|  | #define DEBUG		/* define for debug output */ | 
|  | #endif | 
|  |  | 
|  | #include <config.h> | 
|  | #include <common.h> | 
|  | #include <net.h> | 
|  | #include <miiphy.h> | 
|  | #include <malloc.h> | 
|  | #include <asm/processor.h> | 
|  | #include <asm/arch-ixp/ixp425.h> | 
|  |  | 
|  | #include <IxOsal.h> | 
|  | #include <IxEthAcc.h> | 
|  | #include <IxEthDB.h> | 
|  | #include <IxNpeDl.h> | 
|  | #include <IxQMgr.h> | 
|  | #include <IxNpeMh.h> | 
|  | #include <ix_ossl.h> | 
|  | #include <IxFeatureCtrl.h> | 
|  |  | 
|  | #include <npe.h> | 
|  |  | 
|  | #ifdef CONFIG_IXP4XX_NPE | 
|  |  | 
|  | static IxQMgrDispatcherFuncPtr qDispatcherFunc = NULL; | 
|  | static int npe_exists[NPE_NUM_PORTS]; | 
|  | static int npe_used[NPE_NUM_PORTS]; | 
|  |  | 
|  | /* A little extra so we can align to cacheline. */ | 
|  | static u8 npe_alloc_pool[NPE_MEM_POOL_SIZE + CFG_CACHELINE_SIZE - 1]; | 
|  | static u8 *npe_alloc_end; | 
|  | static u8 *npe_alloc_free; | 
|  |  | 
|  | static void *npe_alloc(int size) | 
|  | { | 
|  | static int count = 0; | 
|  | void *p = NULL; | 
|  |  | 
|  | size = (size + (CFG_CACHELINE_SIZE-1)) & ~(CFG_CACHELINE_SIZE-1); | 
|  | count++; | 
|  |  | 
|  | if ((npe_alloc_free + size) < npe_alloc_end) { | 
|  | p = npe_alloc_free; | 
|  | npe_alloc_free += size; | 
|  | } else { | 
|  | printf("%s: failed (count=%d, size=%d)!\n", count, size); | 
|  | } | 
|  | return p; | 
|  | } | 
|  |  | 
|  | /* Not interrupt safe! */ | 
|  | static void mbuf_enqueue(IX_OSAL_MBUF **q, IX_OSAL_MBUF *new) | 
|  | { | 
|  | IX_OSAL_MBUF *m = *q; | 
|  |  | 
|  | IX_OSAL_MBUF_NEXT_PKT_IN_CHAIN_PTR(new) = NULL; | 
|  |  | 
|  | if (m) { | 
|  | while(IX_OSAL_MBUF_NEXT_PKT_IN_CHAIN_PTR(m)) | 
|  | m = IX_OSAL_MBUF_NEXT_PKT_IN_CHAIN_PTR(m); | 
|  | IX_OSAL_MBUF_NEXT_PKT_IN_CHAIN_PTR(m) = new; | 
|  | } else | 
|  | *q = new; | 
|  | } | 
|  |  | 
|  | /* Not interrupt safe! */ | 
|  | static IX_OSAL_MBUF *mbuf_dequeue(IX_OSAL_MBUF **q) | 
|  | { | 
|  | IX_OSAL_MBUF *m = *q; | 
|  | if (m) | 
|  | *q = IX_OSAL_MBUF_NEXT_PKT_IN_CHAIN_PTR(m); | 
|  | return m; | 
|  | } | 
|  |  | 
|  | static void reset_tx_mbufs(struct npe* p_npe) | 
|  | { | 
|  | IX_OSAL_MBUF *m; | 
|  | int i; | 
|  |  | 
|  | p_npe->txQHead = NULL; | 
|  |  | 
|  | for (i = 0; i < CONFIG_DEVS_ETH_INTEL_NPE_MAX_TX_DESCRIPTORS; i++) { | 
|  | m = &p_npe->tx_mbufs[i]; | 
|  |  | 
|  | memset(m, 0, sizeof(*m)); | 
|  |  | 
|  | IX_OSAL_MBUF_MDATA(m) = (void *)&p_npe->tx_pkts[i * NPE_PKT_SIZE]; | 
|  | IX_OSAL_MBUF_MLEN(m) = IX_OSAL_MBUF_PKT_LEN(m) = NPE_PKT_SIZE; | 
|  | mbuf_enqueue(&p_npe->txQHead, m); | 
|  | } | 
|  | } | 
|  |  | 
|  | static void reset_rx_mbufs(struct npe* p_npe) | 
|  | { | 
|  | IX_OSAL_MBUF *m; | 
|  | int i; | 
|  |  | 
|  | p_npe->rxQHead = NULL; | 
|  |  | 
|  | HAL_DCACHE_INVALIDATE(p_npe->rx_pkts, NPE_PKT_SIZE * | 
|  | CONFIG_DEVS_ETH_INTEL_NPE_MAX_RX_DESCRIPTORS); | 
|  |  | 
|  | for (i = 0; i < CONFIG_DEVS_ETH_INTEL_NPE_MAX_RX_DESCRIPTORS; i++) { | 
|  | m = &p_npe->rx_mbufs[i]; | 
|  |  | 
|  | memset(m, 0, sizeof(*m)); | 
|  |  | 
|  | IX_OSAL_MBUF_MDATA(m) = (void *)&p_npe->rx_pkts[i * NPE_PKT_SIZE]; | 
|  | IX_OSAL_MBUF_MLEN(m) = IX_OSAL_MBUF_PKT_LEN(m) = NPE_PKT_SIZE; | 
|  |  | 
|  | if(ixEthAccPortRxFreeReplenish(p_npe->eth_id, m) != IX_SUCCESS) { | 
|  | printf("ixEthAccPortRxFreeReplenish failed for port %d\n", p_npe->eth_id); | 
|  | break; | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | static void init_rx_mbufs(struct npe* p_npe) | 
|  | { | 
|  | p_npe->rxQHead = NULL; | 
|  |  | 
|  | p_npe->rx_pkts = npe_alloc(NPE_PKT_SIZE * | 
|  | CONFIG_DEVS_ETH_INTEL_NPE_MAX_RX_DESCRIPTORS); | 
|  | if (p_npe->rx_pkts == NULL) { | 
|  | printf("alloc of packets failed.\n"); | 
|  | return; | 
|  | } | 
|  |  | 
|  | p_npe->rx_mbufs = (IX_OSAL_MBUF *) | 
|  | npe_alloc(sizeof(IX_OSAL_MBUF) * | 
|  | CONFIG_DEVS_ETH_INTEL_NPE_MAX_RX_DESCRIPTORS); | 
|  | if (p_npe->rx_mbufs == NULL) { | 
|  | printf("alloc of mbufs failed.\n"); | 
|  | return; | 
|  | } | 
|  |  | 
|  | reset_rx_mbufs(p_npe); | 
|  | } | 
|  |  | 
|  | static void init_tx_mbufs(struct npe* p_npe) | 
|  | { | 
|  | p_npe->tx_pkts = npe_alloc(NPE_PKT_SIZE * | 
|  | CONFIG_DEVS_ETH_INTEL_NPE_MAX_TX_DESCRIPTORS); | 
|  | if (p_npe->tx_pkts == NULL) { | 
|  | printf("alloc of packets failed.\n"); | 
|  | return; | 
|  | } | 
|  |  | 
|  | p_npe->tx_mbufs = (IX_OSAL_MBUF *) | 
|  | npe_alloc(sizeof(IX_OSAL_MBUF) * | 
|  | CONFIG_DEVS_ETH_INTEL_NPE_MAX_TX_DESCRIPTORS); | 
|  | if (p_npe->tx_mbufs == NULL) { | 
|  | printf("alloc of mbufs failed.\n"); | 
|  | return; | 
|  | } | 
|  |  | 
|  | reset_tx_mbufs(p_npe); | 
|  | } | 
|  |  | 
|  | /* Convert IX_ETH_PORT_n to IX_NPEMH_NPEID_NPEx */ | 
|  | static int __eth_to_npe(int eth_id) | 
|  | { | 
|  | switch(eth_id) { | 
|  | case IX_ETH_PORT_1: | 
|  | return IX_NPEMH_NPEID_NPEB; | 
|  |  | 
|  | case IX_ETH_PORT_2: | 
|  | return IX_NPEMH_NPEID_NPEC; | 
|  |  | 
|  | case IX_ETH_PORT_3: | 
|  | return IX_NPEMH_NPEID_NPEA; | 
|  | } | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | /* Poll the CSR machinery. */ | 
|  | static void npe_poll(int eth_id) | 
|  | { | 
|  | if (qDispatcherFunc != NULL) { | 
|  | ixNpeMhMessagesReceive(__eth_to_npe(eth_id)); | 
|  | (*qDispatcherFunc)(IX_QMGR_QUELOW_GROUP); | 
|  | } | 
|  | } | 
|  |  | 
|  | /* ethAcc RX callback */ | 
|  | static void npe_rx_callback(u32 cbTag, IX_OSAL_MBUF *m, IxEthAccPortId portid) | 
|  | { | 
|  | struct npe* p_npe = (struct npe *)cbTag; | 
|  |  | 
|  | if (IX_OSAL_MBUF_MLEN(m) > 0) { | 
|  | mbuf_enqueue(&p_npe->rxQHead, m); | 
|  |  | 
|  | if (p_npe->rx_write == ((p_npe->rx_read-1) & (PKTBUFSRX-1))) { | 
|  | debug("Rx overflow: rx_write=%d rx_read=%d\n", | 
|  | p_npe->rx_write, p_npe->rx_read); | 
|  | } else { | 
|  | debug("Received message #%d (len=%d)\n", p_npe->rx_write, | 
|  | IX_OSAL_MBUF_MLEN(m)); | 
|  | memcpy((void *)NetRxPackets[p_npe->rx_write], IX_OSAL_MBUF_MDATA(m), | 
|  | IX_OSAL_MBUF_MLEN(m)); | 
|  | p_npe->rx_len[p_npe->rx_write] = IX_OSAL_MBUF_MLEN(m); | 
|  | p_npe->rx_write++; | 
|  | if (p_npe->rx_write == PKTBUFSRX) | 
|  | p_npe->rx_write = 0; | 
|  |  | 
|  | #ifdef CONFIG_PRINT_RX_FRAMES | 
|  | { | 
|  | u8 *ptr = IX_OSAL_MBUF_MDATA(m); | 
|  | int i; | 
|  |  | 
|  | for (i=0; i<60; i++) { | 
|  | debug("%02x ", *ptr++); | 
|  | } | 
|  | debug("\n"); | 
|  | } | 
|  | #endif | 
|  | } | 
|  |  | 
|  | m = mbuf_dequeue(&p_npe->rxQHead); | 
|  | } else { | 
|  | debug("Received frame with length 0!!!\n"); | 
|  | m = mbuf_dequeue(&p_npe->rxQHead); | 
|  | } | 
|  |  | 
|  | /* Now return mbuf to NPE */ | 
|  | IX_OSAL_MBUF_MLEN(m) = IX_OSAL_MBUF_PKT_LEN(m) = NPE_PKT_SIZE; | 
|  | IX_OSAL_MBUF_NEXT_BUFFER_IN_PKT_PTR(m) = NULL; | 
|  | IX_OSAL_MBUF_FLAGS(m) = 0; | 
|  |  | 
|  | if(ixEthAccPortRxFreeReplenish(p_npe->eth_id, m) != IX_SUCCESS) { | 
|  | debug("npe_rx_callback: Error returning mbuf.\n"); | 
|  | } | 
|  | } | 
|  |  | 
|  | /* ethAcc TX callback */ | 
|  | static void npe_tx_callback(u32 cbTag, IX_OSAL_MBUF *m) | 
|  | { | 
|  | struct npe* p_npe = (struct npe *)cbTag; | 
|  |  | 
|  | debug("%s\n", __FUNCTION__); | 
|  |  | 
|  | IX_OSAL_MBUF_MLEN(m) = IX_OSAL_MBUF_PKT_LEN(m) = NPE_PKT_SIZE; | 
|  | IX_OSAL_MBUF_NEXT_BUFFER_IN_PKT_PTR(m) = NULL; | 
|  | IX_OSAL_MBUF_FLAGS(m) = 0; | 
|  |  | 
|  | mbuf_enqueue(&p_npe->txQHead, m); | 
|  | } | 
|  |  | 
|  |  | 
|  | static int npe_set_mac_address(struct eth_device *dev) | 
|  | { | 
|  | struct npe *p_npe = (struct npe *)dev->priv; | 
|  | IxEthAccMacAddr npeMac; | 
|  |  | 
|  | debug("%s\n", __FUNCTION__); | 
|  |  | 
|  | /* Set MAC address */ | 
|  | memcpy(npeMac.macAddress, dev->enetaddr, 6); | 
|  |  | 
|  | if (ixEthAccPortUnicastMacAddressSet(p_npe->eth_id, &npeMac) != IX_ETH_ACC_SUCCESS) { | 
|  | printf("Error setting unicast address! %02x:%02x:%02x:%02x:%02x:%02x\n", | 
|  | npeMac.macAddress[0], npeMac.macAddress[1], | 
|  | npeMac.macAddress[2], npeMac.macAddress[3], | 
|  | npeMac.macAddress[4], npeMac.macAddress[5]); | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | return 1; | 
|  | } | 
|  |  | 
|  | /* Boot-time CSR library initialization. */ | 
|  | static int npe_csr_load(void) | 
|  | { | 
|  | int i; | 
|  |  | 
|  | if (ixQMgrInit() != IX_SUCCESS) { | 
|  | debug("Error initialising queue manager!\n"); | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | ixQMgrDispatcherLoopGet(&qDispatcherFunc); | 
|  |  | 
|  | if(ixNpeMhInitialize(IX_NPEMH_NPEINTERRUPTS_YES) != IX_SUCCESS) { | 
|  | printf("Error initialising NPE Message handler!\n"); | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | if (npe_used[IX_ETH_PORT_1] && npe_exists[IX_ETH_PORT_1] && | 
|  | ixNpeDlNpeInitAndStart(IX_NPEDL_NPEIMAGE_NPEB_ETH_LEARN_FILTER_SPAN_FIREWALL_VLAN_QOS) | 
|  | != IX_SUCCESS) { | 
|  | printf("Error downloading firmware to NPE-B!\n"); | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | if (npe_used[IX_ETH_PORT_2] && npe_exists[IX_ETH_PORT_2] && | 
|  | ixNpeDlNpeInitAndStart(IX_NPEDL_NPEIMAGE_NPEC_ETH_LEARN_FILTER_SPAN_FIREWALL_VLAN_QOS) | 
|  | != IX_SUCCESS) { | 
|  | printf("Error downloading firmware to NPE-C!\n"); | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | /* don't need this for U-Boot */ | 
|  | ixFeatureCtrlSwConfigurationWrite(IX_FEATURECTRL_ETH_LEARNING, FALSE); | 
|  |  | 
|  | if (ixEthAccInit() != IX_ETH_ACC_SUCCESS) { | 
|  | printf("Error initialising Ethernet access driver!\n"); | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | for (i = 0; i < IX_ETH_ACC_NUMBER_OF_PORTS; i++) { | 
|  | if (!npe_used[i] || !npe_exists[i]) | 
|  | continue; | 
|  | if (ixEthAccPortInit(i) != IX_ETH_ACC_SUCCESS) { | 
|  | printf("Error initialising Ethernet port%d!\n", i); | 
|  | } | 
|  | if (ixEthAccTxSchedulingDisciplineSet(i, FIFO_NO_PRIORITY) != IX_ETH_ACC_SUCCESS) { | 
|  | printf("Error setting scheduling discipline for port %d.\n", i); | 
|  | } | 
|  | if (ixEthAccPortRxFrameAppendFCSDisable(i) != IX_ETH_ACC_SUCCESS) { | 
|  | printf("Error disabling RX FCS for port %d.\n", i); | 
|  | } | 
|  | if (ixEthAccPortTxFrameAppendFCSEnable(i) != IX_ETH_ACC_SUCCESS) { | 
|  | printf("Error enabling TX FCS for port %d.\n", i); | 
|  | } | 
|  | } | 
|  |  | 
|  | return 1; | 
|  | } | 
|  |  | 
|  | static int npe_init(struct eth_device *dev, bd_t * bis) | 
|  | { | 
|  | struct npe *p_npe = (struct npe *)dev->priv; | 
|  | int i; | 
|  | u16 reg_short; | 
|  | int speed; | 
|  | int duplex; | 
|  |  | 
|  | debug("%s: 1\n", __FUNCTION__); | 
|  |  | 
|  | miiphy_read (dev->name, p_npe->phy_no, PHY_BMSR, ®_short); | 
|  |  | 
|  | /* | 
|  | * Wait if PHY is capable of autonegotiation and autonegotiation is not complete | 
|  | */ | 
|  | if ((reg_short & PHY_BMSR_AUTN_ABLE) && !(reg_short & PHY_BMSR_AUTN_COMP)) { | 
|  | puts ("Waiting for PHY auto negotiation to complete"); | 
|  | i = 0; | 
|  | while (!(reg_short & PHY_BMSR_AUTN_COMP)) { | 
|  | /* | 
|  | * Timeout reached ? | 
|  | */ | 
|  | if (i > PHY_AUTONEGOTIATE_TIMEOUT) { | 
|  | puts (" TIMEOUT !\n"); | 
|  | break; | 
|  | } | 
|  |  | 
|  | if ((i++ % 1000) == 0) { | 
|  | putc ('.'); | 
|  | miiphy_read (dev->name, p_npe->phy_no, PHY_BMSR, ®_short); | 
|  | } | 
|  | udelay (1000);	/* 1 ms */ | 
|  | } | 
|  | puts (" done\n"); | 
|  | udelay (500000);	/* another 500 ms (results in faster booting) */ | 
|  | } | 
|  |  | 
|  | speed = miiphy_speed (dev->name, p_npe->phy_no); | 
|  | duplex = miiphy_duplex (dev->name, p_npe->phy_no); | 
|  |  | 
|  | if (p_npe->print_speed) { | 
|  | p_npe->print_speed = 0; | 
|  | printf ("ENET Speed is %d Mbps - %s duplex connection\n", | 
|  | (int) speed, (duplex == HALF) ? "HALF" : "FULL"); | 
|  | } | 
|  |  | 
|  | npe_alloc_end = npe_alloc_pool + sizeof(npe_alloc_pool); | 
|  | npe_alloc_free = (u8 *)(((unsigned)npe_alloc_pool + | 
|  | CFG_CACHELINE_SIZE - 1) & ~(CFG_CACHELINE_SIZE - 1)); | 
|  |  | 
|  | /* initialize mbuf pool */ | 
|  | init_rx_mbufs(p_npe); | 
|  | init_tx_mbufs(p_npe); | 
|  |  | 
|  | if (ixEthAccPortRxCallbackRegister(p_npe->eth_id, npe_rx_callback, | 
|  | (u32)p_npe) != IX_ETH_ACC_SUCCESS) { | 
|  | printf("can't register RX callback!\n"); | 
|  | return -1; | 
|  | } | 
|  |  | 
|  | if (ixEthAccPortTxDoneCallbackRegister(p_npe->eth_id, npe_tx_callback, | 
|  | (u32)p_npe) != IX_ETH_ACC_SUCCESS) { | 
|  | printf("can't register TX callback!\n"); | 
|  | return -1; | 
|  | } | 
|  |  | 
|  | npe_set_mac_address(dev); | 
|  |  | 
|  | if (ixEthAccPortEnable(p_npe->eth_id) != IX_ETH_ACC_SUCCESS) { | 
|  | printf("can't enable port!\n"); | 
|  | return -1; | 
|  | } | 
|  |  | 
|  | p_npe->active = 1; | 
|  |  | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | #if 0 /* test-only: probably have to deal with it when booting linux (for a clean state) */ | 
|  | /* Uninitialize CSR library. */ | 
|  | static void npe_csr_unload(void) | 
|  | { | 
|  | ixEthAccUnload(); | 
|  | ixEthDBUnload(); | 
|  | ixNpeMhUnload(); | 
|  | ixQMgrUnload(); | 
|  | } | 
|  |  | 
|  | /* callback which is used by ethAcc to recover RX buffers when stopping */ | 
|  | static void npe_rx_stop_callback(u32 cbTag, IX_OSAL_MBUF *m, IxEthAccPortId portid) | 
|  | { | 
|  | debug("%s\n", __FUNCTION__); | 
|  | } | 
|  |  | 
|  | /* callback which is used by ethAcc to recover TX buffers when stopping */ | 
|  | static void npe_tx_stop_callback(u32 cbTag, IX_OSAL_MBUF *m) | 
|  | { | 
|  | debug("%s\n", __FUNCTION__); | 
|  | } | 
|  | #endif | 
|  |  | 
|  | static void npe_halt(struct eth_device *dev) | 
|  | { | 
|  | struct npe *p_npe = (struct npe *)dev->priv; | 
|  | int i; | 
|  |  | 
|  | debug("%s\n", __FUNCTION__); | 
|  |  | 
|  | /* Delay to give time for recovery of mbufs */ | 
|  | for (i = 0; i < 100; i++) { | 
|  | npe_poll(p_npe->eth_id); | 
|  | udelay(100); | 
|  | } | 
|  |  | 
|  | #if 0 /* test-only: probably have to deal with it when booting linux (for a clean state) */ | 
|  | if (ixEthAccPortRxCallbackRegister(p_npe->eth_id, npe_rx_stop_callback, | 
|  | (u32)p_npe) != IX_ETH_ACC_SUCCESS) { | 
|  | debug("Error registering rx callback!\n"); | 
|  | } | 
|  |  | 
|  | if (ixEthAccPortTxDoneCallbackRegister(p_npe->eth_id, npe_tx_stop_callback, | 
|  | (u32)p_npe) != IX_ETH_ACC_SUCCESS) { | 
|  | debug("Error registering tx callback!\n"); | 
|  | } | 
|  |  | 
|  | if (ixEthAccPortDisable(p_npe->eth_id) != IX_ETH_ACC_SUCCESS) { | 
|  | debug("npe_stop: Error disabling NPEB!\n"); | 
|  | } | 
|  |  | 
|  | /* Delay to give time for recovery of mbufs */ | 
|  | for (i = 0; i < 100; i++) { | 
|  | npe_poll(p_npe->eth_id); | 
|  | udelay(10000); | 
|  | } | 
|  |  | 
|  | /* | 
|  | * For U-Boot only, we are probably launching Linux or other OS that | 
|  | * needs a clean slate for its NPE library. | 
|  | */ | 
|  | #if 0 /* test-only */ | 
|  | for (i = 0; i < IX_ETH_ACC_NUMBER_OF_PORTS; i++) { | 
|  | if (npe_used[i] && npe_exists[i]) | 
|  | if (ixNpeDlNpeStopAndReset(__eth_to_npe(i)) != IX_SUCCESS) | 
|  | printf("Failed to stop and reset NPE B.\n"); | 
|  | } | 
|  | #endif | 
|  |  | 
|  | #endif | 
|  | p_npe->active = 0; | 
|  | } | 
|  |  | 
|  |  | 
|  | static int npe_send(struct eth_device *dev, volatile void *packet, int len) | 
|  | { | 
|  | struct npe *p_npe = (struct npe *)dev->priv; | 
|  | u8 *dest; | 
|  | int err; | 
|  | IX_OSAL_MBUF *m; | 
|  |  | 
|  | debug("%s\n", __FUNCTION__); | 
|  | m = mbuf_dequeue(&p_npe->txQHead); | 
|  | dest = IX_OSAL_MBUF_MDATA(m); | 
|  | IX_OSAL_MBUF_PKT_LEN(m) = IX_OSAL_MBUF_MLEN(m) = len; | 
|  | IX_OSAL_MBUF_NEXT_PKT_IN_CHAIN_PTR(m) = NULL; | 
|  |  | 
|  | memcpy(dest, (char *)packet, len); | 
|  |  | 
|  | if ((err = ixEthAccPortTxFrameSubmit(p_npe->eth_id, m, IX_ETH_ACC_TX_DEFAULT_PRIORITY)) | 
|  | != IX_ETH_ACC_SUCCESS) { | 
|  | printf("npe_send: Can't submit frame. err[%d]\n", err); | 
|  | mbuf_enqueue(&p_npe->txQHead, m); | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | #ifdef DEBUG_PRINT_TX_FRAMES | 
|  | { | 
|  | u8 *ptr = IX_OSAL_MBUF_MDATA(m); | 
|  | int i; | 
|  |  | 
|  | for (i=0; i<IX_OSAL_MBUF_MLEN(m); i++) { | 
|  | printf("%02x ", *ptr++); | 
|  | } | 
|  | printf(" (tx-len=%d)\n", IX_OSAL_MBUF_MLEN(m)); | 
|  | } | 
|  | #endif | 
|  |  | 
|  | npe_poll(p_npe->eth_id); | 
|  |  | 
|  | return len; | 
|  | } | 
|  |  | 
|  | static int npe_rx(struct eth_device *dev) | 
|  | { | 
|  | struct npe *p_npe = (struct npe *)dev->priv; | 
|  |  | 
|  | debug("%s\n", __FUNCTION__); | 
|  | npe_poll(p_npe->eth_id); | 
|  |  | 
|  | debug("%s: rx_write=%d rx_read=%d\n", __FUNCTION__, p_npe->rx_write, p_npe->rx_read); | 
|  | while (p_npe->rx_write != p_npe->rx_read) { | 
|  | debug("Reading message #%d\n", p_npe->rx_read); | 
|  | NetReceive(NetRxPackets[p_npe->rx_read], p_npe->rx_len[p_npe->rx_read]); | 
|  | p_npe->rx_read++; | 
|  | if (p_npe->rx_read == PKTBUFSRX) | 
|  | p_npe->rx_read = 0; | 
|  | } | 
|  |  | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | int npe_initialize(bd_t * bis) | 
|  | { | 
|  | static int virgin = 0; | 
|  | struct eth_device *dev; | 
|  | int eth_num = 0; | 
|  | struct npe *p_npe = NULL; | 
|  |  | 
|  | for (eth_num = 0; eth_num < CFG_NPE_NUMS; eth_num++) { | 
|  |  | 
|  | /* See if we can actually bring up the interface, otherwise, skip it */ | 
|  | switch (eth_num) { | 
|  | default:		/* fall through */ | 
|  | case 0: | 
|  | if (memcmp (bis->bi_enetaddr, "\0\0\0\0\0\0", 6) == 0) { | 
|  | continue; | 
|  | } | 
|  | break; | 
|  | #ifdef CONFIG_HAS_ETH1 | 
|  | case 1: | 
|  | if (memcmp (bis->bi_enet1addr, "\0\0\0\0\0\0", 6) == 0) { | 
|  | continue; | 
|  | } | 
|  | break; | 
|  | #endif | 
|  | } | 
|  |  | 
|  | /* Allocate device structure */ | 
|  | dev = (struct eth_device *)malloc(sizeof(*dev)); | 
|  | if (dev == NULL) { | 
|  | printf ("%s: Cannot allocate eth_device %d\n", __FUNCTION__, eth_num); | 
|  | return -1; | 
|  | } | 
|  | memset(dev, 0, sizeof(*dev)); | 
|  |  | 
|  | /* Allocate our private use data */ | 
|  | p_npe = (struct npe *)malloc(sizeof(struct npe)); | 
|  | if (p_npe == NULL) { | 
|  | printf("%s: Cannot allocate private hw data for eth_device %d", | 
|  | __FUNCTION__, eth_num); | 
|  | free(dev); | 
|  | return -1; | 
|  | } | 
|  | memset(p_npe, 0, sizeof(struct npe)); | 
|  |  | 
|  | switch (eth_num) { | 
|  | default:		/* fall through */ | 
|  | case 0: | 
|  | memcpy(dev->enetaddr, bis->bi_enetaddr, 6); | 
|  | p_npe->eth_id = 0; | 
|  | p_npe->phy_no = CONFIG_PHY_ADDR; | 
|  | break; | 
|  |  | 
|  | #ifdef CONFIG_HAS_ETH1 | 
|  | case 1: | 
|  | memcpy(dev->enetaddr, bis->bi_enet1addr, 6); | 
|  | p_npe->eth_id = 1; | 
|  | p_npe->phy_no = CONFIG_PHY1_ADDR; | 
|  | break; | 
|  | #endif | 
|  | } | 
|  |  | 
|  | sprintf(dev->name, "NPE%d", eth_num); | 
|  | dev->priv = (void *)p_npe; | 
|  | dev->init = npe_init; | 
|  | dev->halt = npe_halt; | 
|  | dev->send = npe_send; | 
|  | dev->recv = npe_rx; | 
|  |  | 
|  | p_npe->print_speed = 1; | 
|  |  | 
|  | if (0 == virgin) { | 
|  | virgin = 1; | 
|  |  | 
|  | if (ixFeatureCtrlDeviceRead() == IX_FEATURE_CTRL_DEVICE_TYPE_IXP42X) { | 
|  | switch (ixFeatureCtrlProductIdRead() & IX_FEATURE_CTRL_SILICON_STEPPING_MASK) { | 
|  | case IX_FEATURE_CTRL_SILICON_TYPE_B0: | 
|  | /* | 
|  | * If it is B0 Silicon, we only enable port when its corresponding | 
|  | * Eth Coprocessor is available. | 
|  | */ | 
|  | if (ixFeatureCtrlComponentCheck(IX_FEATURECTRL_ETH0) == | 
|  | IX_FEATURE_CTRL_COMPONENT_ENABLED) | 
|  | npe_exists[IX_ETH_PORT_1] = TRUE; | 
|  |  | 
|  | if (ixFeatureCtrlComponentCheck(IX_FEATURECTRL_ETH1) == | 
|  | IX_FEATURE_CTRL_COMPONENT_ENABLED) | 
|  | npe_exists[IX_ETH_PORT_2] = TRUE; | 
|  | break; | 
|  | case IX_FEATURE_CTRL_SILICON_TYPE_A0: | 
|  | /* | 
|  | * If it is A0 Silicon, we enable both as both Eth Coprocessors | 
|  | * are available. | 
|  | */ | 
|  | npe_exists[IX_ETH_PORT_1] = TRUE; | 
|  | npe_exists[IX_ETH_PORT_2] = TRUE; | 
|  | break; | 
|  | } | 
|  | } else if (ixFeatureCtrlDeviceRead() == IX_FEATURE_CTRL_DEVICE_TYPE_IXP46X) { | 
|  | if (ixFeatureCtrlComponentCheck(IX_FEATURECTRL_ETH0) == | 
|  | IX_FEATURE_CTRL_COMPONENT_ENABLED) | 
|  | npe_exists[IX_ETH_PORT_1] = TRUE; | 
|  |  | 
|  | if (ixFeatureCtrlComponentCheck(IX_FEATURECTRL_ETH1) == | 
|  | IX_FEATURE_CTRL_COMPONENT_ENABLED) | 
|  | npe_exists[IX_ETH_PORT_2] = TRUE; | 
|  | } | 
|  |  | 
|  | npe_used[IX_ETH_PORT_1] = 1; | 
|  | npe_used[IX_ETH_PORT_2] = 1; | 
|  |  | 
|  | npe_alloc_end = npe_alloc_pool + sizeof(npe_alloc_pool); | 
|  | npe_alloc_free = (u8 *)(((unsigned)npe_alloc_pool + | 
|  | CFG_CACHELINE_SIZE - 1) | 
|  | & ~(CFG_CACHELINE_SIZE - 1)); | 
|  |  | 
|  | if (!npe_csr_load()) | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | eth_register(dev); | 
|  |  | 
|  | #if defined(CONFIG_MII) || defined(CONFIG_CMD_MII) | 
|  | miiphy_register(dev->name, npe_miiphy_read, npe_miiphy_write); | 
|  | #endif | 
|  |  | 
|  | }			/* end for each supported device */ | 
|  |  | 
|  | return 1; | 
|  | } | 
|  |  | 
|  | #endif /* CONFIG_IXP4XX_NPE */ |