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 + -
显示快捷键?