This is the mail archive of the ecos-discuss@sources.redhat.com mailing list for the eCos project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Re: Ethernet driver for IXP425 with interrupt.


Hello all,

> >
> > Sometimes ago I add interrupt to Ethernet driver for
> > IXP425 (XScale). If
> > someone is interested in this driver I attach source
> > file.
I added ( I hope correct -> test pass) stopping driver.

Best regards,
jerzy
//==========================================================================
//
//      if_npe.c
//
//	Intel NPE ethernet driver
//
//==========================================================================
//####ECOSGPLCOPYRIGHTBEGIN####
// -------------------------------------------
// This file is part of eCos, the Embedded Configurable Operating System.
// Copyright 2002-2003 Intel Corporation All Rights Reserved.
//
// eCos 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 or (at your option) any later version.
//
// eCos 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 eCos; if not, write to the Free Software Foundation, Inc.,
// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
//
// As a special exception, if other files instantiate templates or use macros
// or inline functions from this file, or you compile this file and link it
// with other works to produce a work based on this file, this file does not
// by itself cause the resulting work to be covered by the GNU General Public
// License. However the source code for this file must still be made available
// in accordance with section (3) of the GNU General Public License.
//
// This exception does not invalidate any other reasons why a work based on
// this file might be covered by the GNU General Public License.
//
// Alternative licenses for eCos may be arranged by contacting Red Hat, Inc.
// at http://sources.redhat.com/ecos/ecos-license/
// -------------------------------------------
//####ECOSGPLCOPYRIGHTEND####
//==========================================================================
//#####DESCRIPTIONBEGIN####
//
// Author(s):    msalter
// Contributors: msalter
// Date:         2003-03-20
// Purpose:      
// Description:  hardware driver for Intel Network Processors.
// Notes:
//
//####DESCRIPTIONEND####
//
//==========================================================================

#include <pkgconf/system.h>
#include <pkgconf/io_eth_drivers.h>
#include <pkgconf/devs_eth_intel_npe.h>
#include <cyg/infra/cyg_type.h>
#include <cyg/infra/cyg_ass.h>
#include <cyg/hal/hal_arch.h>
#include <cyg/hal/hal_cache.h>
#include <cyg/hal/hal_intr.h>
#include <cyg/infra/diag.h>
#include <cyg/hal/hal_if.h>
#include <cyg/hal/drv_api.h>
#include <cyg/io/eth/netdev.h>
#include <cyg/io/eth/eth_drv.h>

#include <IxNpeDl.h>
#include <IxQMgr.h>
#include <IxNpeMh.h>
#include <IxEthAcc.h>
#include <ix_ossl.h>
#include <IxFeatureCtrl.h>

#include <npe_info.h>


#ifdef CYGPKG_REDBOOT
#include <pkgconf/redboot.h>
#include <redboot.h>
#include <flash_config.h>
#endif

#define NPE_INT_BITS ((1 << CYGNUM_HAL_INTERRUPT_NPEB) | \
                      (1 << CYGNUM_HAL_INTERRUPT_NPEC) | \
                      (1 << CYGNUM_HAL_INTERRUPT_QM1))

#include CYGDAT_DEVS_ETH_INTEL_NPE_INL

#ifdef CYGSEM_INTEL_NPE_USE_ETH0
static struct npe npe_eth0_priv_data = { 
    npe_id: CYGNUM_ETH0_NPE_ID,
    eth_id: CYGNUM_ETH0_ETH_ID,
    phy_no: CYGNUM_ETH0_PHY_NO,
#if defined(CYGSEM_NPE_REDBOOT_HOLDS_ESA)
    mac_address: CYGDAT_ETH0_DEFAULT_ESA
#endif
};
#endif

#ifdef CYGSEM_INTEL_NPE_USE_ETH1
static struct npe npe_eth1_priv_data = { 
    npe_id: CYGNUM_ETH1_NPE_ID,
    eth_id: CYGNUM_ETH1_ETH_ID,
    phy_no: CYGNUM_ETH1_PHY_NO,
#if defined(CYGSEM_NPE_REDBOOT_HOLDS_ESA)
    mac_address: CYGDAT_ETH1_DEFAULT_ESA
#endif
};
#endif

#ifdef CYGSEM_NPE_REDBOOT_HOLDS_ESA
#ifdef CYGSEM_INTEL_NPE_USE_ETH0
RedBoot_config_option("Network hardware address [MAC] for NPE eth0",
                      npe_eth0_esa,
                      ALWAYS_ENABLED, true,
                      CONFIG_ESA, npe_eth0_priv_data.mac_address
    );
#endif CYGSEM_INTEL_NPE_USE_ETH0

#ifdef CYGSEM_INTEL_NPE_USE_ETH1
RedBoot_config_option("Network hardware address [MAC] for NPE eth1",
                      npe_eth1_esa,
                      ALWAYS_ENABLED, true,
                      CONFIG_ESA, npe_eth1_priv_data.mac_address
    );
#endif // CYGSEM_INTEL_NPE_USE_ETH1
#endif // CYGSEM_NPE_REDBOOT_HOLDS_ESA

#if defined(CYGSEM_INTEL_NPE_USE_ETH0) && defined(CYGSEM_INTEL_NPE_USE_ETH1)
#define MAX_PORTS 2
#else
#define MAX_PORTS 1
#endif

#ifdef CYGPKG_REDBOOT
#define ACTIVE_PORTS 1
#else
#define ACTIVE_PORTS MAX_PORTS
#endif

#define NPE_PKT_SIZE 1600

#define NPE_MBUF_POOL_SIZE                               \
	((CYGNUM_DEVS_ETH_INTEL_NPE_MAX_TX_DESCRIPTORS + \
 	 CYGNUM_DEVS_ETH_INTEL_NPE_MAX_RX_DESCRIPTORS) * \
	sizeof(M_BLK) * ACTIVE_PORTS)

#define NPE_PKT_POOL_SIZE                                \
	((CYGNUM_DEVS_ETH_INTEL_NPE_MAX_TX_DESCRIPTORS + \
 	 CYGNUM_DEVS_ETH_INTEL_NPE_MAX_RX_DESCRIPTORS) * \
	NPE_PKT_SIZE * ACTIVE_PORTS)

#define NPE_MEM_POOL_SIZE (NPE_MBUF_POOL_SIZE + NPE_PKT_POOL_SIZE)


// A little extra so we can align to cacheline.
static cyg_uint8 npe_alloc_pool[NPE_MEM_POOL_SIZE + HAL_DCACHE_LINE_SIZE - 1];
static cyg_uint8 *npe_alloc_end;
static cyg_uint8 *npe_alloc_free;

/* values used inside the irq */
#ifdef NPE_USE_INTS

static IxQMgrDispatcherFuncPtr dispatcherFunc;
static cyg_sem_t npedriverRun;

#endif // NPE_USE_INTS

// for npedriver thread 

#define npedriver_SS (8*1024)
static cyg_thread npedriverThread;
static cyg_handle_t npedriverHand;
static unsigned char npedriverStack [npedriver_SS];		
static void npedriverThreadFunc(cyg_addrword_t );


static void*
npe_alloc(int size)
{
    void *p = NULL;

    size = (size + (HAL_DCACHE_LINE_SIZE-1)) & ~(HAL_DCACHE_LINE_SIZE-1);
    if ((npe_alloc_free + size) < npe_alloc_end) {
        p = npe_alloc_free;
        npe_alloc_free += size;
    }
    return p;
}


// Not interrupt safe!
static void
mbuf_enqueue(M_BLK **q, M_BLK *new)
{
    IX_MBUF *m = *q;

    new->m_nextpkt = NULL;
    if (m) {
        while(m->m_nextpkt)
            m = m->m_nextpkt;
        m->m_nextpkt = new;
    } else
        *q = new;
}

// Not interrupt safe!
static M_BLK *
mbuf_dequeue(M_BLK **q)
{
    M_BLK *m = *q;
    if (m)
	*q = m->m_nextpkt;
    return m;
}

static void
tx_mbuf_enqueue(M_BLK **q, M_BLK *new)
{
    IX_MBUF *m = *q;

    new->m_nextpkt = NULL;
    if (m) {
        while(m->m_nextpkt)
            m = m->m_nextpkt;
        m->m_nextpkt = new;
    } else
        *q = new;
}

// Not interrupt safe!
static M_BLK *
tx_mbuf_dequeue(M_BLK **q)
{
    M_BLK *m = *q;
    if (m)
	*q = m->m_nextpkt;
    return m;
}


static void
reset_tx_mbufs(struct npe* p_npe)
{
    M_BLK *m;
    int i;

    p_npe->txQHead = NULL;

    for (i = 0; i < CYGNUM_DEVS_ETH_INTEL_NPE_MAX_TX_DESCRIPTORS; i++) {
	m = &p_npe->tx_mbufs[i];
	m->m_data = (char *)&p_npe->tx_pkts[i * NPE_PKT_SIZE];
#ifdef __LITTLE_ENDIAN
	m->m_data = (char *)(((unsigned)m->m_data) | 0x30000000);
#endif
	m->m_len = m->mBlkPktHdr.len = NPE_PKT_SIZE;
	m->m_next = NULL;
	m->m_flags = 0;
	tx_mbuf_enqueue(&p_npe->txQHead, m);
    }
}

static void
reset_rx_mbufs(struct npe* p_npe)
{
    M_BLK *m;
    int i;

    p_npe->rxQHead = NULL;

    HAL_DCACHE_INVALIDATE(p_npe->rx_pkts, NPE_PKT_SIZE *
			  CYGNUM_DEVS_ETH_INTEL_NPE_MAX_RX_DESCRIPTORS);
 
    for (i = 0; i < CYGNUM_DEVS_ETH_INTEL_NPE_MAX_RX_DESCRIPTORS; i++) {
	m = &p_npe->rx_mbufs[i];
	m->m_data = (char *)&p_npe->rx_pkts[i * NPE_PKT_SIZE];
#ifdef __LITTLE_ENDIAN
	m->m_data = (char *)(((unsigned)m->m_data) | 0x30000000);
#endif
	m->m_len = m->mBlkPktHdr.len = NPE_PKT_SIZE;
	m->m_next = NULL;
	m->m_flags = 0;

	if(ixEthAccPortRxFreeReplenish(p_npe->eth_id, m) != IX_SUCCESS) {
#ifdef DEBUG
	    diag_printf("ixEthAccPortRxFreeReplenish failed for port %d\n",
			p_npe->eth_id);
#endif
	    break;
	}
    }
}

static void
init_rx_mbufs(struct npe* p_npe)
{
    p_npe->rxQHead = NULL;

    p_npe->rx_pkts = npe_alloc(NPE_PKT_SIZE *
			       CYGNUM_DEVS_ETH_INTEL_NPE_MAX_RX_DESCRIPTORS);
    if (p_npe->rx_pkts == NULL) {
#ifdef DEBUG
	diag_printf("alloc of packets failed.\n");
#endif
	return;
    }

    p_npe->rx_mbufs = (M_BLK *)npe_alloc(sizeof(M_BLK) *
					 CYGNUM_DEVS_ETH_INTEL_NPE_MAX_RX_DESCRIPTORS);
    if (p_npe->rx_mbufs == NULL) {
#ifdef DEBUG
	diag_printf("alloc of mbufs failed.\n");
#endif
	return;
    }

    reset_rx_mbufs(p_npe);
}


static void
init_tx_mbufs(struct npe* p_npe)
{
    p_npe->tx_pkts = npe_alloc(NPE_PKT_SIZE *
			       CYGNUM_DEVS_ETH_INTEL_NPE_MAX_TX_DESCRIPTORS);
    if (p_npe->tx_pkts == NULL) {
#ifdef DEBUG
	diag_printf("alloc of packets failed.\n");
#endif
	return;
    }

    p_npe->tx_mbufs = (M_BLK *)npe_alloc(sizeof(M_BLK) *
					 CYGNUM_DEVS_ETH_INTEL_NPE_MAX_TX_DESCRIPTORS);
    if (p_npe->tx_mbufs == NULL) {
#ifdef DEBUG
	diag_printf("alloc of mbufs failed.\n");
#endif
	return;
    }

    reset_tx_mbufs(p_npe);
}


#define NPE_VERSIONS_COUNT 16
static int
npeDownload(cyg_uint32 npeId, cyg_uint32 buildId)
{
    cyg_uint32 i, n;
    IxNpeDlVersionId list[NPE_VERSIONS_COUNT];
    IxNpeDlVersionId dlVersion;
    int major, minor;

    if (ixNpeDlAvailableVersionsCountGet(&n) != IX_SUCCESS) {
#ifdef DEBUG
	diag_printf("ixNpeDlAvailableVersionsCountGet failed!\n");
#endif
	return 0;
    }

    if (n > NPE_VERSIONS_COUNT) {
#ifdef DEBUG
	diag_printf("npeDownload: too many versions [%d]!\n", n);
#endif
	return 0;
    }

    if (ixNpeDlAvailableVersionsListGet(list, &n) != IX_SUCCESS) {
#ifdef DEBUG
	diag_printf("ixNpeDlAvailableVersionsListGet failed!\n");
#endif
	return 0;
    }
    
    major = minor = 0;
    for (i = 0; i < n; i++) {
        if (list[i].npeId == npeId) {
            if (list[i].buildId == buildId) {
		if (list[i].major > major) {
		    major = list[i].major;
		    minor = list[i].minor;
                } else if (list[i].major == major && list[i].minor > minor)
		    minor = list[i].minor;
            }
	}
    }

#ifdef DEBUG
    diag_printf("NPE%c major[%d] minor[%d] build[%d]\n",
	      npeId  + 'A', major, minor, buildId);
#endif

    if (ixNpeDlNpeStopAndReset(npeId) != IX_SUCCESS) {
#ifdef DEBUG
	diag_printf("npeDownload: Failed to stop/reset NPE%c\n", npeId  + 'A');
#endif
        return 0;
    }

    dlVersion.npeId = npeId;
    dlVersion.buildId = buildId;
    dlVersion.major = major;
    dlVersion.minor = minor;

    if (ixNpeDlVersionDownload(&dlVersion, 1) != IX_SUCCESS) {
#ifdef DEBUG
	diag_printf("Failed to download to NPE%c\n", npeId  + 'A');
#endif
        return 0;
    }

#if 0
    // verify download
    if (ixNpeDlLoadedVersionGet(npeId, &dlVersion) != IX_SUCCESS) {
#ifdef DEBUG
	diag_printf("Failed to upload version from NPE%c\n", npeId  + 'A');
#endif
        return 0;
    }

    if (dlVersion.buildId != buildId || dlVersion.major != major || dlVersion.major != major) {
#ifdef DEBUG
	diag_printf("Failed to verify download NPE%c\n", npeId  + 'A');
#endif
        return 0;
    }
#endif

    return 1;
}


// Returns non-zero if link is up.
static int
link_check(unsigned int phyNo)
{
    BOOL fullDuplex, linkUp, speed, autoneg;

    ixEthAccMiiLinkStatus(phyNo, &linkUp, &speed, &fullDuplex, &autoneg);
    if (linkUp == FALSE) {
	int retry = 20; /* 2 seconds */
#ifdef DEBUG
	diag_printf("Wait for PHY %u to be ready ...", phyNo);
#endif
	while (linkUp == FALSE && retry-- > 0) {
	    CYGACC_CALL_IF_DELAY_US((cyg_int32)100000);
	    ixEthAccMiiLinkStatus(phyNo, &linkUp, &speed, &fullDuplex, &autoneg);
	}
	if (linkUp == FALSE) 
	    return 0;
    }
    return 1;
}

// Returns non-zero if given PHY is present.
static int
phy_present(int phyno)
{
    static BOOL phyPresent[IXP425_ETH_ACC_MII_MAX_ADDR];
    static int scanned = 0;

    if (!scanned) {
	if(ixEthAccMiiPhyScan(phyPresent) != IX_ETH_ACC_SUCCESS)
	    return 0;
	scanned = 1;

#ifdef DEBUG
	{
	    int i;
	    for(i = 0; i < IXP425_ETH_ACC_MII_MAX_ADDR; i++)
		diag_printf("phyPresent[%d] = %d\n", i, phyPresent[i]);
	}
#endif
    }

    return (phyno < (int)(sizeof(phyPresent)/sizeof(phyPresent[0])) && phyPresent[phyno]);
}


// Initialize given PHY for given port.
// Returns non-zero if successful.
static int
phy_init(int portno, int phyno)
{
    BOOL speed, linkUp, fullDuplex, autoneg;

    ixEthAccMiiPhyReset(phyno);

    ixEthAccMiiPhyConfig(phyno, TRUE, TRUE, TRUE);

    // wait until the link is up before setting the MAC duplex
    // mode, the PHY duplex mode may change after autonegotiation 
    (void)link_check(phyno);

    ixEthAccMiiLinkStatus(phyno, &linkUp, &speed, &fullDuplex, &autoneg);

    /* Set the MAC duplex mode */
    ixEthAccPortDuplexModeSet(portno, fullDuplex ? IX_ETH_ACC_FULL_DUPLEX :
				                  IX_ETH_ACC_HALF_DUPLEX);

#ifdef DEBUG
    diag_printf("\nPHY %d configuration:\n", phyno);
    ixEthAccMiiShow(phyno);
#endif

    return 1;
}


// ethAcc RX callback
static void
npe_rx_callback(cyg_uint32 cbTag, M_BLK *m, IxEthAccPortId portid)
{

    struct npe* p_npe = (struct npe *)cbTag;
    struct eth_drv_sc *sc;

    sc = p_npe->sc;

    mbuf_enqueue(&p_npe->rxQHead, m);

#ifdef DEBUG
	diag_printf("npe_rx_callback, eth_recv = 0x%04x, sc_rcv = 0x%04x m_len = %d \n",
	              sc->funs->eth_drv->recv, sc->funs->recv, m->m_len);
#endif

    HAL_DCACHE_INVALIDATE(m->m_data, NPE_PKT_SIZE);

    (sc->funs->eth_drv->recv)(sc, m->m_len);
    
#ifdef DEBUG
	diag_printf("npe_rx_callback : eth_recv\n");
#endif
    // Now return mbuf to NPE
    m->m_len = m->mBlkPktHdr.len = NPE_PKT_SIZE;
    m->m_next = NULL;
    m->m_flags = 0;
    
    HAL_DCACHE_INVALIDATE(m->m_data, NPE_PKT_SIZE);
 
    if(ixEthAccPortRxFreeReplenish(p_npe->eth_id, m) != IX_SUCCESS) {
#ifdef DEBUG
	diag_printf("npe_rx_callback: Error returning mbuf.\n");
#endif
    }    
}

// callback which is used by ethAcc to recover RX buffers when stopping
static void
npe_rx_stop_callback(cyg_uint32 cbTag, M_BLK *m, IxEthAccPortId portid)
{
	struct npe* p_npe = (struct npe *)cbTag;
	
	if(ixEthAccPortRxFreeReplenish(p_npe->eth_id, m) != IX_SUCCESS) {
#ifdef DEBUG
	diag_printf("npe_rx_callback: Error returning mbuf.\n");
#endif
	}
#ifdef DEBUG
	diag_printf("npe_rx_stop_callback\n");
#endif

}


// ethAcc TX callback
static void
npe_tx_callback(cyg_uint32 cbTag, M_BLK *m)
{
    struct npe* p_npe = (struct npe *)cbTag;
    struct eth_drv_sc *sc;

    sc = p_npe->sc;

    (sc->funs->eth_drv->tx_done)(sc, m->m_key, 1);
    
    m->m_len = m->mBlkPktHdr.len = NPE_PKT_SIZE;
    m->m_next = NULL;
    m->m_flags = 0;
    tx_mbuf_enqueue(&p_npe->txQHead, m);
}


// callback which is used by ethAcc to recover TX buffers when stopping
static void
npe_tx_stop_callback(cyg_uint32 cbTag, M_BLK *m)
{
#ifdef DEBUG
	diag_printf("npe_tx_stop_callback\n");
#endif

}

#ifdef NPE_USE_INTS
static cyg_uint32
npe_isr(cyg_vector_t vector, cyg_addrword_t data)
{
	/* Mask the interrupt */
	cyg_interrupt_mask(vector);
	/* Acknowledge the interrupt for those platforms were this is necessary */
	cyg_interrupt_acknowledge(vector);
    
#ifdef DEBUG
	diag_printf("\n1.npe_isr\n");
#endif
 	return (CYG_ISR_HANDLED | CYG_ISR_CALL_DSR);

}

// ------------------------------------------------------------------------

static void
npe_dsr(cyg_vector_t vector, cyg_ucount32 count, cyg_addrword_t data)
{
#ifdef DEBUG
	diag_printf("npe_dsr=%d,vec=%d\n", count, vector);
#endif
  
	cyg_semaphore_post(&npedriverRun);
  
#ifdef DEBUG
	diag_printf("npe_dsr : done\n", count, vector);
#endif
  
}
#endif //NPE_USE_INTS


void
npedriverThreadFunc(cyg_addrword_t param)
{
    struct eth_drv_sc *sc = (struct eth_drv_sc *) param;
    struct npe *p_npe = (struct npe *)sc->driver_private;

#ifdef DEBUG
	diag_printf("npedriverThreadFunc : thread start\n");
#endif

	while(true){
  
#ifdef NPE_USE_INTS
      
		cyg_semaphore_wait(&npedriverRun);

		// call the queue manager entry point and clear the source of interrupt
		dispatcherFunc(IX_QMGR_QUELOW_GROUP);
      
		//interrupt is unmask after taking mbuff from queue  
		cyg_interrupt_unmask(p_npe->vector);   
#else //non-int version of thread                                    
         
		cyg_thread_delay(2);  // wait 20ms
		npe_poll(sc);
      
#endif //NPE_USE_INTS
      
	}
}


// return non-zero if hardware has NPEC
static inline int
npec_present(void)
{
    if ((ixFeatureCtrlProductIdRead() & IX_FEATURE_CTRL_SILICON_STEPPING_MASK) == 
         IX_FEATURE_CTRL_SILICON_TYPE_B0) 
    {
        if (ixFeatureCtrlComponentCheck(IX_FEATURECTRL_ETH1) == IX_FEATURE_CTRL_COMPONENT_DISABLED)
	    return 0;
    }
    return 1;
}

// ------------------------------------------------------------------------
//
//  API Function : npe_init
//
// ------------------------------------------------------------------------
static bool
npe_init(struct cyg_netdevtab_entry * ndp)
{
    static int initialized = 0;
    struct eth_drv_sc *sc;
    struct npe *p_npe;
    int mac_ok = false;
    IxEthAccMacAddr  npeMac;
    cyg_uint8 bus, dev, func;

    sc = (struct eth_drv_sc *)ndp->device_instance;
    p_npe = (struct npe *)sc->driver_private;

    p_npe->sc = sc;

    p_npe->active = 0;

    

#ifdef DEBUG
	    diag_printf("\nStart initialising NPE!\n");
	    diag_printf("npe_id = %d, eth_id = %d, phy_no = %d\n",
	                 p_npe->npe_id, p_npe->eth_id , p_npe->phy_no);
#endif

#ifdef CYGHWR_NET_DRIVER_ETH3
    if (!npec_present() && p_npe == &npe_eth1_priv_data)
		return 0;
#endif
    if (!initialized) {
		// One time initialization common to all ports
		initialized = 1;
		npe_alloc_end = npe_alloc_pool + sizeof(npe_alloc_pool);
		npe_alloc_free = (cyg_uint8 *)(((unsigned)npe_alloc_pool + HAL_DCACHE_LINE_SIZE - 1)
				       & ~(HAL_DCACHE_LINE_SIZE - 1));

		if (ixQMgrInit() != IX_SUCCESS) {
#ifdef DEBUG
	    	diag_printf("Error initialising queue manager!\n");
#endif
	    	return 0;
		}

#ifdef NPE_USE_INTS

        /* Get the dispatcher entrypoint */
        ixQMgrDispatcherLoopGet (&dispatcherFunc);
#endif //NPE_USE_INTS

        if (!npeDownload(IX_NPEDL_NPEID_NPEB, 0)) {
#ifdef DEBUG
	    	diag_printf("npeDownload failed (NPEB)!\n");
#endif
	    	return 0;
		}
#ifdef CYGHWR_NET_DRIVER_ETH3
		if (npec_present() && !npeDownload(IX_NPEDL_NPEID_NPEC, 0)) {
#ifdef DEBUG
	    	diag_printf("npeDownload failed (NPEC)!\n");
#endif
	    	return 0;
		}
#endif

		if(ixNpeMhInitialize(IX_NPEMH_NPEINTERRUPTS_YES) != IX_SUCCESS) {
#ifdef DEBUG
	    	diag_printf("Error initialising NPE Message handler!\n");
#endif
	    	return 0;
		}

		if(ixNpeDlNpeExecutionStart(IX_NPEDL_NPEID_NPEB) != IX_SUCCESS) {
#ifdef DEBUG
	    	diag_printf("Error starting NPEB!\n");
#endif
	    	return 0;
		}

#ifdef CYGHWR_NET_DRIVER_ETH3
		if(npec_present() && ixNpeDlNpeExecutionStart(IX_NPEDL_NPEID_NPEC) != IX_SUCCESS) {
#ifdef DEBUG
	    	diag_printf("Error starting NPEB!\n");
#endif
	    	return 0;
		}
#endif

		if (ixEthAccInit() != IX_ETH_ACC_SUCCESS) {
#ifdef DEBUG
	    	diag_printf("Error initialising Ethernet access driver!\n");
#endif
	    	return 0;
		}

		if(ixEthAccPortInit(IX_ETH_PORT_1) != IX_ETH_ACC_SUCCESS) {
#ifdef DEBUG
	    	diag_printf("Error initialising Ethernet port1!\n");	
#endif
	    	return 0;
		}

#ifdef CYGHWR_NET_DRIVER_ETH3
		if(npec_present() && ixEthAccPortInit(IX_ETH_PORT_2) != IX_ETH_ACC_SUCCESS) {
#ifdef DEBUG
	    	diag_printf("Error initialising Ethernet port2!\n");	
#endif
	    	return 0;
		}
#endif	
    }

    if (!phy_present(p_npe->phy_no)) {
#ifdef DEBUG
		diag_printf("No phy for NPE%c found!\n", 'A' + p_npe->npe_id);
#endif
		return 0;
    }

    if(!phy_init(p_npe->eth_id, p_npe->phy_no)) {
#ifdef DEBUG
		diag_printf("Error initialising Ethernet phy(s)!\n");
#endif
		return 0;
    }

    // Set MAC address
#if defined(CYGSEM_NPE_REDBOOT_HOLDS_ESA)
    {
	char *cfgname = NULL;
#if defined(CYGSEM_INTEL_NPE_USE_ETH0)
	if (p_npe == &npe_eth0_priv_data)
	    cfgname = "npe_eth0_esa";
#endif
#if defined(CYGSEM_INTEL_NPE_USE_ETH1)
	if (p_npe == &npe_eth1_priv_data)
	    cfgname = "npe_eth1_esa";
#endif
        
#elif defined(CYGHAL_GET_NPE_ESA)
    
        mac_ok = CYGACC_CALL_IF_FLASH_CFG_OP(CYGNUM_CALL_IF_FLASH_CFG_GET, cfgname,
					     p_npe->mac_address, CONFIG_ESA);
    }
#else
#error No mechanism to get MAC address
#endif

    if (!mac_ok) {
#ifdef DEBUG
		diag_printf("Error getting MAC address.\n");
#endif
		return 0;
    }

    npeMac.macAddress[0] = p_npe->mac_address[0];
    npeMac.macAddress[1] = p_npe->mac_address[1];
    npeMac.macAddress[2] = p_npe->mac_address[2];
    npeMac.macAddress[3] = p_npe->mac_address[3];
    npeMac.macAddress[4] = p_npe->mac_address[4];
    npeMac.macAddress[5] = p_npe->mac_address[5];

#ifdef DEBUG
    diag_printf("npe_init: MAC Address = %02X %02X %02X %02X %02X %02X\n",
              p_npe->mac_address[0], p_npe->mac_address[1],
              p_npe->mac_address[2], p_npe->mac_address[3],
              p_npe->mac_address[4], p_npe->mac_address[5]);
#endif

    ixEthAccPortUnicastMacAddressSet(p_npe->eth_id, &npeMac);


    // initialize mbuf pool
    init_rx_mbufs(p_npe);
    init_tx_mbufs(p_npe);

    // set scheduling discipline
    ixEthAccTxSchedulingDisciplineSet(p_npe->eth_id, FIFO_NO_PRIORITY);


    if (ixEthAccPortRxCallbackRegister(p_npe->eth_id, npe_rx_callback,
				       (cyg_uint32)p_npe) != IX_ETH_ACC_SUCCESS) {
#ifdef DEBUG
		diag_printf("Error registering rx callback!\n");
#endif
		return 0;
    }
    
    if (ixEthAccPortTxDoneCallbackRegister(p_npe->eth_id, npe_tx_callback,
					   (cyg_uint32)p_npe) != IX_ETH_ACC_SUCCESS) {
#ifdef DEBUG
		diag_printf("Error registering tx callback!\n");
#endif
		return 0;
    }

    if (ixEthAccPortRxFrameAppendFCSDisable(p_npe->eth_id) != IX_ETH_ACC_SUCCESS) {
#ifdef DEBUG
		diag_printf("Error disabling RX FCS.\n");
#endif
		return 0;
    }

    if(ixEthAccPortTxFrameAppendFCSEnable(p_npe->eth_id) != IX_ETH_ACC_SUCCESS) {
#ifdef DEBUG
		diag_printf("Error enabling TX FCS.\n");
#endif
		return 0;
    }
    // Initialize upper level driver
    (sc->funs->eth_drv->init)(sc, &(p_npe->mac_address[0]) );
 
    
#ifdef DEBUG
	diag_printf("npe_init, active=%d\n", p_npe->active);
#endif

   
    return 1;
}

// ------------------------------------------------------------------------
//
//  API Function : npe_start
//
// ------------------------------------------------------------------------
static void 
npe_start( struct eth_drv_sc *sc, unsigned char *enaddr, int flags )
{

static int started = 0;

#ifndef CYGPKG_REDBOOT
    struct npe *p_npe = (struct npe *)sc->driver_private;

#ifdef DEBUG
	diag_printf("npe_start, active=%d\n", p_npe->active);
#endif

    if(!p_npe->active){
		if (ixEthAccPortRxCallbackRegister(p_npe->eth_id, npe_rx_callback,
					(cyg_uint32)p_npe) != IX_ETH_ACC_SUCCESS) {
#ifdef DEBUG
			diag_printf("Error registering rx callback!\n");
#endif
		}

		if (ixEthAccPortTxDoneCallbackRegister(p_npe->eth_id, npe_tx_callback,
						(cyg_uint32)p_npe) != IX_ETH_ACC_SUCCESS) {
#ifdef DEBUG
			diag_printf("Error registering tx callback!\n");
#endif
		}

		if(!started){
    		started = 1;
#ifdef NPE_USE_INTS
			p_npe->vector = IXP425_INT_LVL_QM1;
			cyg_drv_interrupt_create(p_npe->vector, 0, (CYG_ADDRWORD)sc, npe_isr, npe_dsr,
				&p_npe->interrupt_handle, &p_npe->interrupt);
			cyg_drv_interrupt_attach(p_npe->interrupt_handle);
                   
			// create semaphore for npe driver thread 
			cyg_semaphore_init(&npedriverRun, 0);

#endif // NPE_USE_INTS

			// start npedriver thread 
			cyg_thread_create(8, npedriverThreadFunc, (CYG_ADDRWORD)sc,"npe driver thread", 
				&npedriverStack[0], npedriver_SS, &npedriverHand, &npedriverThread);
		}

		if(ixEthAccPortEnable(p_npe->eth_id) != IX_ETH_ACC_SUCCESS) {
#ifdef DEBUG
			diag_printf("npe_start: Error enabling NPE%c!\n", 'A' + p_npe->npe_id);
#endif 	
		}
		//Without this function eth receiver seems disabled.
		if(ixEthAccPortRxEnable(p_npe->eth_id) != IX_ETH_ACC_SUCCESS) {
#ifdef DEBUG
			diag_printf("npe_stop: Error disabling NPEB!\n");
#endif
    	}

#ifdef NPE_USE_INTS
        
		if (p_npe->interrupt_handle != 0){ 
			cyg_drv_interrupt_acknowledge(p_npe->vector);
			cyg_drv_interrupt_unmask(p_npe->vector);
      	
#ifdef DEBUG
			diag_printf("npe_init: isr enable vec = %d\n", p_npe->vector);
#endif
		}
#endif // NPE_USE_INTS

    	cyg_thread_resume(npedriverHand);
    	p_npe->active = 1;
    }
#endif
}

// ------------------------------------------------------------------------
//
//  API Function : npe_stop
//
// ------------------------------------------------------------------------
static void
npe_stop( struct eth_drv_sc *sc )
{

cyg_bool enabled;
struct npe *p_npe = (struct npe *)sc->driver_private;
    
#ifdef NPE_USE_INTS
	cyg_drv_interrupt_mask(p_npe->vector);

#ifdef DEBUG
    diag_printf("npe_start: isr disable vec = %d\n", p_npe->vector);
#endif

#endif //NPE_USE_INTS
	
	cyg_thread_suspend(npedriverHand);  // Stop it
              
    if(ixEthAccPortEnabledQuery(p_npe->eth_id,&enabled) != IX_ETH_ACC_SUCCESS) {
#ifdef DEBUG
		diag_printf("npe_stop:invalid port number!\n");
#endif
    }
#ifdef DEBUG
		diag_printf("npe_stop:port is %d!\n",enabled);
#endif

        
    if (ixEthAccPortRxCallbackRegister(p_npe->eth_id, npe_rx_stop_callback,
				       (cyg_uint32)p_npe) != IX_ETH_ACC_SUCCESS) {
#ifdef DEBUG
		diag_printf("Error registering rx callback!\n");
#endif
    }

    if (ixEthAccPortTxDoneCallbackRegister(p_npe->eth_id, npe_tx_stop_callback,
					   (cyg_uint32)p_npe) != IX_ETH_ACC_SUCCESS) {
#ifdef DEBUG
		diag_printf("Error registering tx callback!\n");
#endif
    }
	
	if(ixEthAccPortRxDisable(p_npe->eth_id) != IX_ETH_ACC_SUCCESS) {
#ifdef DEBUG
		diag_printf("npe_stop: Error disabling RX NPEB!\n");
#endif
    }

    //Clearing QM from unexpected frames 
	ixNpeMhMessagesReceive(p_npe->npe_id);
	ixQMgrDispatcherLoopRun(IX_QMGR_QUELOW_GROUP);
	
    
// For RedBoot only, we are probably launching Linux or other OS that
// needs a clean slate for its NPE library.	
#ifdef CYGPKG_REDBOOT
    if (ixNpeDlNpeStopAndReset(IX_NPEDL_NPEID_NPEB) != IX_SUCCESS)
        diag_printf ("Failed to stop and reset NPE B.\n");

    if (npec_present() && ixNpeDlNpeStopAndReset(IX_NPEDL_NPEID_NPEC) != IX_SUCCESS)
        diag_printf ("Failed to stop and reset NPE C.\n");
#endif

    p_npe->active = 0;
 
}


// ------------------------------------------------------------------------
//
//  API Function : npe_recv
//
// ------------------------------------------------------------------------
static void 
npe_recv( struct eth_drv_sc *sc, struct eth_drv_sg *sg_list, int sg_len )
{
    struct npe *p_npe = (struct npe *)sc->driver_private;
    struct eth_drv_sg *sg = sg_list;
    M_BLK *m;
    cyg_uint8 *src;
    int len;
	    
    m = mbuf_dequeue(&p_npe->rxQHead);
    src = m->m_data;

    while (sg < &sg_list[sg_len]) {
            
        len = sg->len;

        if (len < 0 || sg->buf == 0)
            return;

        if (len > m->m_len)
            len = m->m_len;

        memcpy((char *)sg->buf, src, len);
        src += len;
        m->m_len -= len;

	++sg;
    }
#ifdef DEBUG
	diag_printf("npe_recv : done,number of npe_recv = %d\n", ++cnt_npe_recv);
#endif
    
}

// ------------------------------------------------------------------------
//
//  API Function : npe_can_send
//
// ------------------------------------------------------------------------
static int 
npe_can_send(struct eth_drv_sc *sc)
{
    struct npe *p_npe = (struct npe *)sc->driver_private;

    if(	p_npe->txQHead == NULL){
#ifdef DEBUG
    diag_printf("npe can't send!\n");
#endif
    
    }

    return p_npe->active && p_npe->txQHead != NULL;
}

// ------------------------------------------------------------------------
//
//  API Function : npe_send
//
// ------------------------------------------------------------------------
static void 
npe_send(struct eth_drv_sc *sc,
	 struct eth_drv_sg *sg_list, int sg_len,
	 int total_len, unsigned long key)
{
    struct npe *p_npe = (struct npe *)sc->driver_private;
    struct eth_drv_sg *sg = sg_list;
    cyg_uint8 *dest;
    int len, err;
    M_BLK *m;

    m = tx_mbuf_dequeue(&p_npe->txQHead);

    dest = m->m_data;
    if (total_len > m->m_len)
	total_len = m->m_len;

    m->mBlkPktHdr.len = m->m_len = total_len;
    m->m_key = key;
    m->m_nextpkt = NULL;

    while (sg < &sg_list[sg_len] && total_len > 0) {

	len = sg->len;
	if (len > total_len)
	    len = total_len;

	memcpy(dest, (char *)sg->buf, len);

	dest += len;
	total_len -= len;

	++sg;
    }

    HAL_DCACHE_FLUSH(m->m_data, m->m_len);

    if((err = ixEthAccPortTxFrameSubmit(p_npe->eth_id, m, IX_ETH_ACC_TX_DEFAULT_PRIORITY))
       != IX_ETH_ACC_SUCCESS) {
#ifdef DEBUG
	diag_printf("npe_send: Can't submit frame. err[%d]\n", err);
#endif
	tx_mbuf_enqueue(&p_npe->txQHead, m);
	return;
    }
}

// ------------------------------------------------------------------------
//
//  API Function : npe_deliver
//
// ------------------------------------------------------------------------
static void
npe_deliver(struct eth_drv_sc *sc)
{
}

// ------------------------------------------------------------------------
//
//  API Function : npe_poll
//
// ------------------------------------------------------------------------
static void
npe_poll(struct eth_drv_sc *sc)
{
    struct npe *p_npe = (struct npe *)sc->driver_private;
    cyg_uint32 ints;

    if(p_npe->active){
       ints = *IXP425_INTR_EN;
       *IXP425_INTR_EN = ints & ~NPE_INT_BITS;
    
       ixNpeMhMessagesReceive(p_npe->npe_id);
       ixQMgrDispatcherLoopRun (IX_QMGR_QUELOW_GROUP);

       *IXP425_INTR_EN = ints;
    }   
}


// ------------------------------------------------------------------------
//
//  API Function : npe_int_vector
//
// ------------------------------------------------------------------------
static int
npe_int_vector(struct eth_drv_sc *sc)
{
    struct npe *p_npe;
    p_npe = (struct npe *)sc->driver_private;

    if (p_npe->eth_id == IX_ETH_PORT_1)
	return CYGNUM_HAL_INTERRUPT_NPEB;
    else if (p_npe->eth_id == IX_ETH_PORT_2)
	return CYGNUM_HAL_INTERRUPT_NPEC;
    return -1;
}


// ------------------------------------------------------------------------
//
//  API Function : npe_ioctl
//
// ------------------------------------------------------------------------
static int
npe_ioctl(struct eth_drv_sc *sc, unsigned long key,
	  void *data, int data_length)
{
    return -1;
}


#ifdef CYGSEM_INTEL_NPE_USE_ETH0
ETH_DRV_SC(npe_sc0,
           &npe_eth0_priv_data,
           CYGDAT_NPE_ETH0_NAME,
           npe_start,
           npe_stop,
           npe_ioctl,
           npe_can_send,
           npe_send,
           npe_recv,
           npe_deliver,
           npe_poll,
           npe_int_vector);

NETDEVTAB_ENTRY(npe_netdev0, 
                "npe_" CYGDAT_NPE_ETH0_NAME,
                npe_init, 
                &npe_sc0);
#endif // CYGSEM_INTEL_NPE_USE_ETH0

#ifdef CYGSEM_INTEL_NPE_USE_ETH1
ETH_DRV_SC(npe_sc1,
           &npe_eth1_priv_data,
           CYGDAT_NPE_ETH1_NAME,
           npe_start,
           npe_stop,
           npe_ioctl,
           npe_can_send,
           npe_send,
           npe_recv,
           npe_deliver,
           npe_poll,
           npe_int_vector);

NETDEVTAB_ENTRY(npe_netdev1, 
                "npe_" CYGDAT_NPE_ETH1_NAME,
                npe_init, 
                &npe_sc1);
#endif // CYGSEM_INTEL_NPE_USE_ETH1

// ------------------------------------------------------------------------
// EOF if_npe.c

-- 
Before posting, please read the FAQ: http://ecos.sourceware.org/fom/ecos
and search the list archive: http://ecos.sourceware.org/ml/ecos-discuss

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]