681 lines
		
	
	
		
			17 KiB
		
	
	
	
		
			C
		
	
	
	
			
		
		
	
	
			681 lines
		
	
	
		
			17 KiB
		
	
	
	
		
			C
		
	
	
	
/*
 | 
						|
 * (C) Copyright 2005-2006
 | 
						|
 * Stefan Roese, DENX Software Engineering, sr@denx.de.
 | 
						|
 *
 | 
						|
 * SPDX-License-Identifier:	GPL-2.0+
 | 
						|
 */
 | 
						|
 | 
						|
#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>
 | 
						|
 | 
						|
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 + CONFIG_SYS_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 + (CONFIG_SYS_CACHELINE_SIZE-1)) & ~(CONFIG_SYS_CACHELINE_SIZE-1);
 | 
						|
	count++;
 | 
						|
 | 
						|
	if ((npe_alloc_free + size) < npe_alloc_end) {
 | 
						|
		p = npe_alloc_free;
 | 
						|
		npe_alloc_free += size;
 | 
						|
	} else {
 | 
						|
		printf("npe_alloc: 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__);
 | 
						|
 | 
						|
#ifdef CONFIG_MII_NPE0_FIXEDLINK
 | 
						|
	if (0 == p_npe->eth_id) {
 | 
						|
		speed = CONFIG_MII_NPE0_SPEED;
 | 
						|
		duplex = CONFIG_MII_NPE0_FULLDUPLEX ? FULL : HALF;
 | 
						|
	} else
 | 
						|
#endif
 | 
						|
#ifdef CONFIG_MII_NPE1_FIXEDLINK
 | 
						|
	if (1 == p_npe->eth_id) {
 | 
						|
		speed = CONFIG_MII_NPE1_SPEED;
 | 
						|
		duplex = CONFIG_MII_NPE1_FULLDUPLEX ? FULL : HALF;
 | 
						|
	} else
 | 
						|
#endif
 | 
						|
	{
 | 
						|
		miiphy_read(dev->name, p_npe->phy_no, MII_BMSR, ®_short);
 | 
						|
 | 
						|
		/*
 | 
						|
		 * Wait if PHY is capable of autonegotiation and
 | 
						|
		 * autonegotiation is not complete
 | 
						|
		 */
 | 
						|
		if ((reg_short & BMSR_ANEGCAPABLE) &&
 | 
						|
		    !(reg_short & BMSR_ANEGCOMPLETE)) {
 | 
						|
			puts("Waiting for PHY auto negotiation to complete");
 | 
						|
			i = 0;
 | 
						|
			while (!(reg_short & BMSR_ANEGCOMPLETE)) {
 | 
						|
				/*
 | 
						|
				 * Timeout reached ?
 | 
						|
				 */
 | 
						|
				if (i > PHY_AUTONEGOTIATE_TIMEOUT) {
 | 
						|
					puts(" TIMEOUT !\n");
 | 
						|
					break;
 | 
						|
				}
 | 
						|
 | 
						|
				if ((i++ % 1000) == 0) {
 | 
						|
					putc('.');
 | 
						|
					miiphy_read(dev->name, p_npe->phy_no,
 | 
						|
						     MII_BMSR, ®_short);
 | 
						|
				}
 | 
						|
				udelay(1000);	/* 1 ms */
 | 
						|
			}
 | 
						|
			puts(" done\n");
 | 
						|
			/* another 500 ms (results in faster booting) */
 | 
						|
			udelay(500000);
 | 
						|
		}
 | 
						|
		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 +
 | 
						|
				 CONFIG_SYS_CACHELINE_SIZE - 1) & ~(CONFIG_SYS_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, 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;
 | 
						|
	uchar enetaddr[6];
 | 
						|
 | 
						|
	for (eth_num = 0; eth_num < CONFIG_SYS_NPE_NUMS; eth_num++) {
 | 
						|
 | 
						|
		/* See if we can actually bring up the interface, otherwise, skip it */
 | 
						|
#ifdef CONFIG_HAS_ETH1
 | 
						|
		if (eth_num == 1) {
 | 
						|
			if (!eth_getenv_enetaddr("eth1addr", enetaddr))
 | 
						|
				continue;
 | 
						|
		} else
 | 
						|
#endif
 | 
						|
			if (!eth_getenv_enetaddr("ethaddr", enetaddr))
 | 
						|
				continue;
 | 
						|
 | 
						|
		/* 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));
 | 
						|
 | 
						|
		p_npe->eth_id = eth_num;
 | 
						|
		memcpy(dev->enetaddr, enetaddr, 6);
 | 
						|
#ifdef CONFIG_HAS_ETH1
 | 
						|
		if (eth_num == 1)
 | 
						|
			p_npe->phy_no = CONFIG_PHY1_ADDR;
 | 
						|
		else
 | 
						|
#endif
 | 
						|
			p_npe->phy_no = CONFIG_PHY_ADDR;
 | 
						|
 | 
						|
		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:
 | 
						|
				default: /* newer than B0 */
 | 
						|
					/*
 | 
						|
					 * If it is B0 or newer 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 +
 | 
						|
						 CONFIG_SYS_CACHELINE_SIZE - 1)
 | 
						|
						& ~(CONFIG_SYS_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;
 | 
						|
}
 |