⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 ins_eth_ocm.c

📁 sopc builder 中网络的eth_ocm核
💻 C
📖 第 1 页 / 共 2 页
字号:
#ifdef  ALT_INICHE

#include "ins_eth_ocm.h"

/**
 * Function for obtaining MAC address. Located externally in application code.
 *
 * @param net  NET interface (Interniche typedef)
 * @param mac_addr Character array into which MAC address should be written.
 *
 * @return zero on success, nonzero otherwise.
 */ 
extern int get_mac_addr(NET net, unsigned char mac_addr[6]);

/**
 * Performs PHY initialization and determines link duplex.
 * This is fully vendor specific depending on the PHY you are using.
 *
 * @param  dev Pointer to eth_ocm_dev struct which contains needed base address
 * @return 1 if Link is established in Full duplex.
 *         0 if Link is established in Half duplex.
 */
extern int eth_ocm_phy_init(eth_ocm_dev *dev);

static void eth_ocm_isr(void *context, alt_u32 id);
static int  eth_ocm_read_init(eth_ocm_dev *dev);
#ifndef ETH_OCM_SYNC_TX
static int  eth_ocm_pkt_send(PACKET pkt);
static int  eth_ocm_low_send(NET net, char *data, unsigned data_bytes);
static void eth_ocm_tx_isr(eth_ocm_dev *dev);
#else
static int  eth_ocm_raw_send(NET net, char *data, unsigned data_bytes);
#endif // else ifndef ETH_OCM_SYNC_TX
static int  eth_ocm_rx_isr(eth_ocm_dev *dev);

/**
 * Prepare ethernet MAC.
 *
 * @param ins_dev   Pointer to associated alt_iniche_dev struct
 * @return
 */
error_t eth_ocm_prep(alt_iniche_dev *ins_dev){
    NET ifp;
    int index;
    eth_ocm_dev *dev;

    index = ins_dev->if_num;
    dev = (eth_ocm_dev *)ins_dev;

    #if (ETH_OCM_DBG_LVL >= 1)
    //Status message
    dprintf("eth_ocm_prep\n");
    #endif // if ETH_OCM_DBG_LVL

    //create eth_ocm_info struct
    dev->info = (eth_ocm_info *)malloc(sizeof(eth_ocm_info));
    dev->info->sem = 0; //initialize semaphore
    dev->info->rx_pkts = (PACKET *)(malloc(sizeof(PACKET) * ETH_OCM_RX_DESC_COUNT));


    ifp = nets[index];
    ifp->n_mib->ifAdminStatus = ETH_OCM_STATUS_DOWN;    
    ifp->n_mib->ifOperStatus =  ETH_OCM_STATUS_DOWN;
    ifp->n_mib->ifLastChange =  cticks * (100/TPS);     //timestamp
    ifp->n_mib->ifPhysAddress = (u_char*)dev->info->mac_addr;
    ifp->n_mib->ifDescr =       (u_char*)"Opencores 10/100 ethernet MAC";
    ifp->n_lnh =                ETHHDR_SIZE;            /* ethernet header size. */
    ifp->n_hal =                ETH_OCM_MAC_ADDR_LEN;   /* MAC address length */
    ifp->n_mib->ifType =        ETHERNET;               /* device type */
    ifp->n_mtu =                ETH_OCM_MAX_MTU;        /* max frame size */

    /* install our hardware driver routines */
    ifp->n_init =       eth_ocm_init;
    #ifndef ETH_OCM_SYNC_TX
    ifp->pkt_send =     eth_ocm_pkt_send;
    ifp->raw_send =     NULL;
    #else
    ifp->pkt_send =     NULL;
    ifp->raw_send =     eth_ocm_raw_send;
    #endif // ifndef ETH_OCM_SYNC_TX
    ifp->n_close =      eth_ocm_close;
    ifp->n_stats =      eth_ocm_stats;

#ifdef IP_V6
      ifp->n_flags |= (NF_NBPROT | NF_IPV6);
#else
      ifp->n_flags |= NF_NBPROT;
#endif

    /* set cross-pointers between iface and eth_ocm structs */
    dev->info->netp = ifp;
    ifp->n_local = (void*)(dev);

    /* get the MAC address. */
    get_mac_addr(ifp, dev->info->mac_addr);

    index++;
    return index;
}
//End of function eth_ocm_prep

/**
 * Initializes the Opencores ethernet MAC. Called by InterNiche stack
 *
 * @param 
 */
int eth_ocm_init(int iface){
    int status = SUCCESS;
    int duplex;
    int temp;
    NET ifp;
    eth_ocm_dev *dev;
    eth_ocm_info *info;
    eth_ocm_regs *regs;

    #if (ETH_OCM_DBG_LVL >= 1)
    dprintf("[eth_ocm_init]\n");
    #endif
    //get the ifp first
    ifp = nets[iface];
    //now get the info pointer
    dev = (eth_ocm_dev *)ifp->n_local;
    info = dev->info;
    regs = dev->regs;

    //Reset Descriptors (supposedly this can be done while in reset)
    for(temp=ETH_OCM_DESC_START;temp<ETH_OCM_DESC_END;temp++)
        IOWR(dev->base, temp, 0);

    //Let's disable the MAC until everything else is set up
    regs->moder = 0;

    //Determine the number of RX descriptors
    regs->tx_bd_num = ETH_OCM_TX_DESC_COUNT; //Set TX descriptor count in MAC    
    info->cur_tx_desc = 0;
    info->cur_rx_desc = 0;
    #ifndef ETH_OCM_SYNC_TX
    info->next_tx_desc = 0;
    info->next_tx_desc_rdy = 1;
    //Initialize queues
    dev->info->tosend.q_head = dev->info->tosend.q_tail = NULL;
    dev->info->tosend.q_max = dev->info->tosend.q_min = dev->info->tosend.q_len = 0;
    dev->info->sending.q_head = dev->info->sending.q_tail = NULL;
    dev->info->sending.q_max = dev->info->sending.q_min = dev->info->sending.q_len = 0;
    #endif

    /* perform any necessary PHY setup */
    //Let's set the MDIO interface up to run at 4MHz.
    temp = (ALT_CPU_FREQ / 1000000);
    temp += 2;
    temp &= 0xFFFFFFFE;   //only even numbers allowed)
    regs->miimoder = temp;
    regs->miicommand = 0;
    //Find out if we should run in duplex or not
    duplex = eth_ocm_phy_init(dev);

    if(duplex)
        duplex = ETH_OCM_MODER_FULLD_MSK;

    // Configure MAC options
    // Interrupt sources
    regs->int_mask = ETH_OCM_DEFAULT_INTERRUPT_MASK; //Interrupt on receive
    // Clear any existing interrupts
    regs->int_source = 0xFFFFFFFF;

    // Inter-packet gap 
    if(duplex)
        regs->ipgt = ETH_OCM_FULL_DUPLEX_IPGT; 
    else
        regs->ipgt = ETH_OCM_HALF_DUPLEX_IPGT;

    //Let's set the defaults just because they've bitten us before
    regs->ipgr2     = 0x0000000C;
    regs->ipgr2     = 0x00000012;
    regs->packetlen = 0x00400600;  //Min and Max frame sizes
    regs->collconf  = 0x000F003F;
    regs->ctrlmoder = 0x00000000;

    #if (ETH_OCM_DBG_LVL >= 1)
    dprintf("[eth_ocm_init] Configuring MAC address "
            "%02x:%02x:%02x:%02x:%02x:%02x\n",
            info->mac_addr[0],info->mac_addr[1],info->mac_addr[2],
            info->mac_addr[3],info->mac_addr[4],info->mac_addr[5]);
    #endif // if ETH_OCM_DBG_LVL
    //Configure the MAC address
    regs->mac_addr0 =
            ( ((int)info->mac_addr[5])         |
             (((int)info->mac_addr[4]) << 8)   |
             (((int)info->mac_addr[3]) << 16)  |
             (((int)info->mac_addr[2]) << 24)  );

    regs->mac_addr1 =
            ( ((int)((unsigned char)info->mac_addr[1]))         |
             (((int)((unsigned char)info->mac_addr[0])) << 8)   );


    //Enable MAC
    regs->moder = (
           ETH_OCM_MODER_PAD_MSK    |   //Enable padding of small packets
           ETH_OCM_MODER_CRCEN_MSK  |   //Append CRC to TX packets
           ETH_OCM_MODER_RXEN_MSK   |   //Enable receive
           ETH_OCM_MODER_TXEN_MSK   |   //Enable transmit
           duplex                       //Discovered duplex
           );

    #if (ETH_OCM_DBG_LVL >= 1)
    dprintf("\nOpencores MAC post-init: MODER = 0x%08x\n", (int)regs->moder);
    #endif // if ETH_OCM_DBG

   /* status = UP */
   nets[iface]->n_mib->ifAdminStatus = ETH_OCM_STATUS_UP;
   nets[iface]->n_mib->ifOperStatus = ETH_OCM_STATUS_UP;

   //register ISR interrupt handler
   temp = alt_irq_register(dev->irq, dev, eth_ocm_isr);
   if(temp)
       dprintf("[eth_ocm_init] Failed to register RX ISR\n");
   //Setup the first read transfer
   eth_ocm_read_init(dev);

   return status;   //MAC is ready to rock and roll
}
//End of eth_ocm_init function


#ifndef ETH_OCM_SYNC_TX
int eth_ocm_pkt_send(PACKET pkt){
    eth_ocm_dev *dev;
    eth_ocm_info *info;
    eth_ocm_regs *regs;
    int result;
#ifdef UCOS_II
    int cpu_sr;
#endif

    dev = (eth_ocm_dev *)pkt->net->n_local;
    info = dev->info;
    regs = dev->regs;
    result = SUCCESS;

    OS_ENTER_CRITICAL();    //disable interrupts

    putq(&info->tosend, (qp)pkt);
    eth_ocm_tx_isr(dev);
    /*
    //If there is an available descriptor, and it's not busy
    if(info->next_tx_desc_rdy && (info->sending.q_len < ETH_OCM_TX_DESC_COUNT)){//!(regs->txdescs[info->next_tx_desc].ctrl & ETH_OCM_TXDESC_READY_MSK)){
        result = eth_ocm_low_send(pkt->net, pkt->nb_prot, pkt->nb_plen);
        //If setup failed, free the packet and move on.
        if(result != SUCCESS){
            pkt->net->n_mib->ifOutDiscards++; //increment TX discard counter
            pk_free(pkt);
            return result;
        }
        else{ //Transfer was successfully setup
            info->next_tx_desc++;
            if(info->next_tx_desc == ETH_OCM_TX_DESC_COUNT)
                info->next_tx_desc = 0;
            //See if all descriptor are in use
            if(info->next_tx_desc == info->cur_tx_desc)
                info->next_tx_desc_rdy = 0;
            //Put the packet in the sending queue
            putq(&info->sending, (qp)pkt);
        }
    }
    else{ //Unable to send packet right now so queue it
        putq(&info->tosend, (qp)pkt);
    }
    */

    OS_EXIT_CRITICAL();     //reenable interrupts
    return SUCCESS;
}

/** This is the asynchronous raw send function. It sets up a transfer
 *  but does not wait for it to conclude. It sets the MAC to interrupt
 *  when the transfer has finished. This is not threadsafe.
 *
 *  @param NET
 *  @param data
 *  @param data_bytes
 *
 *  @return 0 if Successful, negative otherwise
 */
int eth_ocm_low_send(NET net, char *data, unsigned data_bytes){
    int result;
    unsigned len;
    eth_ocm_dev *dev;
    eth_ocm_info *info;
    eth_ocm_regs *regs;
    alt_u8 *buf;

    dev = (eth_ocm_dev *)net->n_local;
    info = dev->info;
    regs = dev->regs;
    len = data_bytes;
    result = SUCCESS;

    //Check to see if someone is nesting send calls (BAD!)
    if(info->sem){
       dprintf("[eth_ocm_low_send] ERROR: Nested low send call\n");
       return ENP_RESOURCE;
    }
    //Grab the semaphore
    info->sem = 1;
    // clear bit-31 before passing it to SGDMA Driver
    buf = (alt_u8 *)alt_remap_cached( (volatile void *)data, 4);
    //advance the pointer beyond the header bias
    buf = (alt_u8 *)((unsigned int)buf + ETHHDR_BIAS);

    //Some error checks first
    if(len < ETH_OCM_MIN_MTU)
        result = -1;        //packet too small
    if(len > ETH_OCM_MAX_MTU)
        result = -EFBIG;    //packet too big
    if(regs->txdescs[info->next_tx_desc].ctrl & ETH_OCM_TXDESC_READY_MSK)
        result = -EBUSY;    //DMA not available

    if(result == SUCCESS){
        //Write pointer to descriptor
        regs->txdescs[info->next_tx_desc].ptr = (unsigned int)buf;
        //Write length and setup transfer
        result = ((len << ETH_OCM_TXDESC_LEN_OFST)  |
                 ETH_OCM_TXDESC_READY_MSK           |
                 ETH_OCM_TXDESC_IRQ_MSK             |
                 ETH_OCM_TXDESC_PAD_MSK             |
                 ETH_OCM_TXDESC_CRC_MSK);
        //See if wrap flag should be set
        if(info->next_tx_desc == (ETH_OCM_TX_DESC_COUNT - 1))
            result |= ETH_OCM_TXDESC_WRAP_MSK;
        //Write descriptor
        regs->txdescs[info->next_tx_desc].ctrl = result;
        result = SUCCESS;
    }

    info->sem = 0;
    return result;
}

void    eth_ocm_tx_isr(eth_ocm_dev *dev){
    eth_ocm_info *info;
    eth_ocm_regs *regs;
    int result;
    PACKET pkt;

    info = dev->info;
    regs = dev->regs;

    //First we need to process all finished descriptors
    while(  info->sending.q_len>0 
            && ((info->cur_tx_desc != info->next_tx_desc) || !info->next_tx_desc_rdy)
            && !(regs->txdescs[info->cur_tx_desc].ctrl & ETH_OCM_TXDESC_READY_MSK)){ 
    
        //Get the packet
        pkt = (PACKET)getq(&info->sending);

        //Get transmit result from descriptor
        result = regs->txdescs[info->cur_tx_desc].ctrl;

        //Check for errors
        if(result & 
            (ETH_OCM_TXDESC_UR_MSK      |
            ETH_OCM_TXDESC_RL_MSK       |
            ETH_OCM_TXDESC_LC_MSK       |
            ETH_OCM_TXDESC_CS_MSK)){
            #if (ETH_OCM_DBG_LVL >= 2)
            dprintf("[eth_ocm_tx_isr] Transmit error 0x%x\n", result);
            #endif // if ETH_OCM_DBG_LVL
            pkt->net->n_mib->ifOutDiscards++; //increment TX discard counter
            } 
        else{
            #if (ETH_OCM_DBG_LVL >= 5)
            if(result & ETH_OCM_TXDESC_RTRY_MSK)
                dprintf("[eth_ocm_tx_isr] Transmit retries: %d\n", (result & ETH_OCM_TXDESC_RTRY_MSK)>>ETH_OCM_TXDESC_RTRY_OFST);
            #endif
            pkt->net->n_mib->ifOutOctets += pkt->nb_plen;
            pkt->net->n_mib->ifOutUcastPkts++;
            result = 0;
        }

        //free the packet
        pk_free(pkt);

        //Increment the current descriptor pointer
        info->cur_tx_desc++;
        if(info->cur_tx_desc == ETH_OCM_TX_DESC_COUNT)
            info->cur_tx_desc = 0;
        //Whatever the next descriptor is it's ready now
        info->next_tx_desc_rdy = 1;
    }

    //Now we can send any queued packets
    while( info->next_tx_desc_rdy
            && info->tosend.q_len>0
            && !(regs->txdescs[info->next_tx_desc].ctrl & ETH_OCM_TXDESC_READY_MSK) ){

        //Get the packet to be send
        pkt = (PACKET)getq(&info->tosend);

        result = eth_ocm_low_send(pkt->net, pkt->nb_prot, pkt->nb_plen);
        //If setup failed, free the packet and move on.
        if(result != SUCCESS){
            pkt->net->n_mib->ifOutDiscards++;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -