if_i82544.c

来自「eCos操作系统源码」· C语言 代码 · 共 2,128 行 · 第 1/5 页

C
2,128
字号
    ioaddr = p_i82544->io_address; // get 82544's I/O address    status = INL(ioaddr + I82544_STATUS);    return status;}// ------------------------------------------------------------------------////  Function : BringDown82544//// ------------------------------------------------------------------------static voidi82544_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 voidInitRxRing(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 voidPacketRxReady(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 functionstatic 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 voidInitTxRing(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 td = p_i82544->tx_ring + (i*I82544_TD_SIZE);        WRITEMEM64( td + I82544_TD_BUFFER, 0 );    }    // Set the transmitter queue registers    OUTL( VIRT_TO_BUS(p_i82544->tx_ring), ioaddr + I82544_TDBAL );    OUTL( 0, ioaddr + I82544_TDBAH );    OUTL( MAX_TX_DESCRIPTORS * I82544_TD_SIZE, ioaddr + I82544_TDLEN );    OUTL( 0, ioaddr + I82544_TDH );    OUTL( 0, ioaddr + I82544_TDT );    // Set IPG values    OUTL( 8 | (8<<10) | (6<<20), ioaddr + I82544_TIPG );        // Program tx ctrl register    txctl = INL( ioaddr + I82544_TCTL );    txctl |= (15<<4);   // collision threshold    txctl |= (64<<12);  // collision distance    txctl |= I82544_TCTL_PSP;    OUTL( txctl, ioaddr + I82544_TCTL );    p_i82544->tx_in_progress = 0;    p_i82544->tx_pointer = 0;        }// ------------------------------------------------------------------------////  Function : TxDone          (Called from delivery thread)//// This returns Tx's from the Tx Machine to the stack (ie. reports// completion) - allowing for missed interrupts, and so on.// ------------------------------------------------------------------------static voidTxDone(struct i82544* p_i82544){    struct cyg_netdevtab_entry *ndp;    struct eth_drv_sc *sc;    cyg_uint32 ioaddr;    cyg_int32 txp = p_i82544->tx_pointer;    #ifdef DEBUG_82544//    db_printf("TxDone\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;      // get device I/O address    if( !p_i82544->active )        return;    for(;;)    {        cyg_uint8 status;        cyg_uint8 cmd;        CYG_ADDRESS dp;        cyg_int32 txh;                txh = INL( ioaddr + I82544_TDH );        // If there has been no advance on the transmit header,        // nothing to do.        if( txh == txp )            break;#ifdef DEBUG_82544        os_printf("TxDone: TxH %04d TxP %04d\n",txh,txp);#endif                        // Get descri

⌨️ 快捷键说明

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