if_i82544.c

来自「开放源码实时操作系统源码.」· C语言 代码 · 共 2,053 行 · 第 1/5 页

C
2,053
字号
                  p_i82544->index );
#endif
        return;
    }

    if ( p_i82544->active )
        i82544_stop( sc );

    // Enable device
    p_i82544->active = 1;

    /* Enable promiscuous mode if requested, reception of oversized frames always.
     * The latter is needed for VLAN support and shouldn't hurt even if we're not
     * using VLANs.
     */
    i82544_configure(p_i82544, 0
#ifdef CYGPKG_NET
                     || !!(ifp->if_flags & IFF_PROMISC)
#endif
#ifdef ETH_DRV_FLAGS_PROMISC_MODE
                     || !!(flags & ETH_DRV_FLAGS_PROMISC_MODE)
#endif
                     , 1);

    // enable receiver
    rxctl = INL( ioaddr + I82544_RCTL );
    rxctl |= I82544_RCTL_EN;
    OUTL( rxctl, ioaddr + I82544_RCTL );

    // Enable transmitter
    txctl = INL( ioaddr + I82544_TCTL );
    txctl |= I82544_TCTL_EN;
    OUTL( txctl, ioaddr + I82544_TCTL );
    
}

// ------------------------------------------------------------------------
//
//  Function : i82544_status
//
// ------------------------------------------------------------------------
int
i82544_status( struct eth_drv_sc *sc )
{
    int status;
    struct i82544 *p_i82544;
    cyg_uint32 ioaddr;
#ifdef DEBUG
    db_printf("i82544_status\n");
#endif
    
    p_i82544 = (struct i82544 *)sc->driver_private;
    
    IF_BAD_82544( p_i82544 ) {
#ifdef DEBUG
        os_printf( "i82544_status: Bad device pointer %x\n", p_i82544 );
#endif
        return 0;
    }

    ioaddr = p_i82544->io_address; // get 82544's I/O address

    status = INL(ioaddr + I82544_STATUS);

    return status;
}

// ------------------------------------------------------------------------
//
//  Function : BringDown82544
//
// ------------------------------------------------------------------------

static void
i82544_stop( struct eth_drv_sc *sc )
{
    struct i82544 *p_i82544;
    cyg_uint32 ioaddr;
    cyg_uint32 txctl, rxctl;
    
#ifdef DEBUG
    db_printf("i82544_stop\n");
#endif
    
    p_i82544 = (struct i82544 *)sc->driver_private;

    IF_BAD_82544( p_i82544 ) {
#ifdef DEBUG
        os_printf( "i82544_stop: Bad device pointer %x\n", p_i82544 );
#endif
        return;
    }
   
#ifdef DEBUG
    os_printf("i82544_stop %d flg %x\n", p_i82544->index, *(int *)p_i82544 );
#endif

    p_i82544->active = 0;               // stop people tormenting it

    ioaddr = p_i82544->io_address;
    
    // disable receiver
    rxctl = INL( ioaddr + I82544_RCTL );
    rxctl &= ~I82544_RCTL_EN;
    OUTL( rxctl, ioaddr + I82544_RCTL );

    // Enable transmitter
    txctl = INL( ioaddr + I82544_TCTL );
    txctl &= ~I82544_TCTL_EN;
    OUTL( txctl, ioaddr + I82544_TCTL );
    
}


// ------------------------------------------------------------------------
//
//  Function : InitRxRing
//
// ------------------------------------------------------------------------

static void
InitRxRing(struct i82544* p_i82544)
{
    int i;
    CYG_ADDRESS rxring;
    cyg_uint32 ioaddr = p_i82544->io_address;    
    cyg_uint32 rxctl;
    
#ifdef DEBUG_82544
    os_printf("InitRxRing %d\n", p_i82544->index);
#endif

    // Allocate array of Rx desriptors
    rxring = pciwindow_mem_alloc(
        MAX_RX_DESCRIPTORS * I82544_RD_SIZE + 32 );

    // assign ring structure, aligning it on a 16 byte boudary.
    p_i82544->rx_ring = (rxring + 15) & ~15;
    
    // Allocate and fill in buffer pointers
    for ( i = 0; i < MAX_RX_DESCRIPTORS; i++) {
        CYG_ADDRESS rd = p_i82544->rx_ring + (i*I82544_RD_SIZE);
        CYG_ADDRESS buf = pciwindow_mem_alloc(MAX_RX_PACKET_SIZE);
        WRITEMEM64( rd + I82544_RD_BUFFER, VIRT_TO_BUS(buf) );
    }

    // Set the receiver queue registers

    OUTL( VIRT_TO_BUS(p_i82544->rx_ring), ioaddr + I82544_RDBAL );
    OUTL( 0, ioaddr + I82544_RDBAH );
    OUTL( MAX_RX_DESCRIPTORS * I82544_RD_SIZE, ioaddr + I82544_RDLEN );
    OUTL( 0, ioaddr + I82544_RDH );
    OUTL( MAX_RX_DESCRIPTORS - 5, ioaddr + I82544_RDT );

    // zero out RAT
    
    for( i = 0; i < 32; i++ )
        OUTL( 0, ioaddr + I82544_RAT +(i*4) );

    // Zero out MTA
    for( i = 0; i < 128; i++ )
        OUTL( 0, ioaddr + I82544_MTA +(i*4) );
    
    // Set up receiver to accept broadcasts
    rxctl = INL( ioaddr + I82544_RCTL );
    rxctl |= I82544_RCTL_BAM;
    OUTL( rxctl, ioaddr + I82544_RCTL );

#ifdef DEBUG_82544
    os_printf("RCTL %08x\n",rxctl);
#endif
    
    p_i82544->next_rx_descriptor = 0;
    p_i82544->rx_pointer = 0;
}

// ------------------------------------------------------------------------
//
//  Function : PacketRxReady     (Called from delivery thread & foreground)
//
// ------------------------------------------------------------------------

static void
PacketRxReady(struct i82544* p_i82544)
{
    struct cyg_netdevtab_entry *ndp;
    struct eth_drv_sc *sc;
    cyg_int32 rxp;
    cyg_uint32 ioaddr;
    
#ifdef DEBUG_82544
//    db_printf("PacketRxReady\n");
#endif
    
    ndp = (struct cyg_netdevtab_entry *)(p_i82544->ndp);
    sc = (struct eth_drv_sc *)(ndp->device_instance);

    CHECK_NDP_SC_LINK();

    ioaddr = p_i82544->io_address;


    rxp = p_i82544->rx_pointer;
    
    for(;;)
    {
        cyg_int32 rxh, rxt;
        CYG_ADDRESS dp;
        cyg_uint8 status;

        rxh = INL( ioaddr + I82544_RDH );

#if 0 //def DEBUG_82544
        os_printf("rxp %04d rxh %04x\n",rxp,rxh);
#endif
        
        // If the head pointer has not advanced, there have been no
        // packets received.
        if( rxh == rxp )
            break;

        // Form packet address
        dp = p_i82544->rx_ring + (rxp * I82544_RD_SIZE);

        // Get status
        READMEM8( dp + I82544_RD_STATUS, status );

#if 0 //def DEBUG_82544
        {
            cyg_uint16 length;
            READMEM16( dp + I82544_RD_LENGTH, length );
            os_printf("rxp %04d status %02x length %d\n",rxp,status,length);
        }
#endif
        
        if( status & I82544_RD_STATUS_EOP )
        {
            cyg_uint16 length;

            READMEM16( dp + I82544_RD_LENGTH, length );

#ifdef DEBUG_82544
        os_printf("rxp %04d length %d\n",rxp,length);
#endif
            CYG_ASSERT( MAX_RX_PACKET_SIZE >= length, "Oversize Rx" );

            // tell the callback the right packet
            p_i82544->next_rx_descriptor = rxp;

#ifdef CYGPKG_NET
            if ( length > sizeof( struct ether_header ) )
            // then it is acceptable; offer the data to the network stack
#endif
            (sc->funs->eth_drv->recv)( sc, length );

            // All done!
        }

        // Advance rxp pointer
        rxp = ( rxp + 1 ) % MAX_RX_DESCRIPTORS;

        // We can now also advance the tail pointer by 1
        rxt = INL( ioaddr + I82544_RDT );
        dp = p_i82544->rx_ring + (rxt * I82544_RD_SIZE);
        WRITEMEM8( dp + I82544_RD_STATUS, status );
        rxt = ( rxt + 1 ) % MAX_RX_DESCRIPTORS;
        OUTL( rxt, ioaddr + I82544_RDT );
        
#ifdef CYGPKG_IO_ETH_DRIVERS_STAND_ALONE
	// Can't deliver more than one packet in polled standalone mode
	break;
#endif
    }

    // Save next rx pointer for next time.
    p_i82544->rx_pointer = rxp;
    
}

// and the callback function

static void 
i82544_recv( struct eth_drv_sc *sc, struct eth_drv_sg *sg_list, int sg_len )
{
    struct i82544 *p_i82544;
    cyg_int32 rxp;
    CYG_ADDRESS dp;
    CYG_ADDRESS from_p;
    cyg_uint16 total_len;
    struct eth_drv_sg *last_sg;
    
#ifdef DEBUG_82544
    db_printf("i82544_recv\n");
#endif
    
    p_i82544 = (struct i82544 *)sc->driver_private;
    
    IF_BAD_82544( p_i82544 ) {
#ifdef DEBUG_82544
        os_printf( "i82544_recv: Bad device pointer %x\n", p_i82544 );
#endif
        return;
    }

    rxp = p_i82544->next_rx_descriptor;
    // Form packet address
    dp = p_i82544->rx_ring + (rxp * I82544_RD_SIZE);

#if 0 //def DEBUG_82544
        {
            int i;
            os_printf("RxD %08x",dp);
            for( i = 0; i < 16; i++ )
            {
                cyg_uint8 b;
                if( (i%8) == 0 ) os_printf("\n");
                READMEM8( dp + i, b );
                os_printf("%02x ",b);
            }
            os_printf("\n");
        }
#endif        
    // Copy the data to the network stack
    READMEM64( dp + I82544_RD_BUFFER, from_p );
    from_p = BUS_TO_VIRT(from_p);
    READMEM16( dp + I82544_RD_LENGTH, total_len );

#ifdef DEBUG_82544
    db_printf("RXP: %04x len %d\n",rxp,total_len);
#endif
    
    // check we have memory to copy into; we would be called even if
    // caller was out of memory in order to maintain our state.
    if ( 0 == sg_len || 0 == sg_list )
        return; // caller was out of mbufs

    CYG_ASSERT( 0 < sg_len, "sg_len underflow" );
    CYG_ASSERT( MAX_ETH_DRV_SG >= sg_len, "sg_len overflow" );

    for ( last_sg = &sg_list[sg_len]; sg_list < last_sg; sg_list++ ) {
        cyg_uint8 *to_p;
        int l;
            
        to_p = (cyg_uint8 *)(sg_list->buf);
        l = sg_list->len;

        CYG_ASSERT( 0 <= l, "sg length -ve" );

        if ( 0 >= l || 0 == to_p )
            return; // caller was out of mbufs

        if ( l > total_len )
            l = total_len;

#if 0 //def DEBUG_82544
    {
        int i,ll = l;
        os_printf("Pkt len %d",l);
        if( ll > 32 ) ll = 32;
        for( i = 0; i < ll; i++ )
        {
            cyg_uint8 b;
            if( (i%8) == 0 ) os_printf("\n %04x: ",i);
            b = ((cyg_uint8 *)from_p)[i];
            os_printf("%02x ",b);
        }
        os_printf("\n");
        
    }
#endif
        memcpy( to_p, (unsigned char *)from_p, l );
        from_p += l;
        total_len -= l;
    }

    CYG_ASSERT( 0 == total_len, "total_len mismatch in rx" );
    CYG_ASSERT( last_sg == sg_list, "sg count mismatch in rx" );

}


// ------------------------------------------------------------------------
//
//  Function : InitTxRing
//
// ------------------------------------------------------------------------

static void
InitTxRing(struct i82544* p_i82544)
{
    int i;
    cyg_uint32 ioaddr = p_i82544->io_address;
    CYG_ADDRESS txring;
    cyg_uint32 txctl;
    
#ifdef DEBUG_82544
    os_printf("InitTxRing %d\n", p_i82544->index);
#endif

    // Allocate array of Tx desriptors
    txring = pciwindow_mem_alloc(
        MAX_TX_DESCRIPTORS * I82544_TD_SIZE + 32 );

    // assign ring structure, aligning it on a 16 byte boudary.
    p_i82544->tx_ring = (txring + 15) & ~15;
    
    // Allocate and fill in buffer pointers
    for ( i = 0; i < MAX_TX_DESCRIPTORS; i++) {
        CYG_ADDRESS 

⌨️ 快捷键说明

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